Set up

Load libraries

library(tidyverse)
library(readxl)
library(DT)
library(Matrix)
library(patchwork)
library(gridExtra)
library(viridis)
library(RColorBrewer)
library(ComplexHeatmap)
library(circlize)
library(purrr)
library(broom)
#library(broom.mixed)
library(igraph)
library(ggpubr)
library(correlation)
library(ggrepel)
library(ggalluvial)
library(Seurat)
library(clusterProfiler)
library(umap) ## https://github.com/tkonopka/umap/blob/master/vignettes/umap.Rmd
library(tidygraph)
library(ggraph)
library(scales)
library(WGCNA)
library(mixOmics)
library(eulerr)
library(lmerTest)
#library(broom.mixed)
library(emmeans)

Load data

# Malaria Explore 1536 data
data <- utils::read.delim("../data/data/explore1536/20230411_infectious_olink.tsv") 
# Malaria sampleTable
sampleTable_simple <- readRDS("../data/metaData_clean/Explore1536_Malaria_sampleTable_simple.rds")
# Malaria subjectTable
subjectTable <- readRDS("../data/metaData_clean/MalariaResource_subjectTable.rds")
# Malaria clinchem data
clinchem_study_pats_acute.wide <- readRDS("../data/metaData_clean/Explore1536_ClinicalChemistry_acute.rds")

# Tropical fever Explore 1536 data
TF.long <- readRDS("../data/data_clean/Explore1536_TF_tidy_long.rds")
# Tropical fever sampleTable
TF_sampleTable <- readRDS("../data/metaData_clean/Explore1536_TF_sampleTable.rds")


# HPA v24
hpa_24.0 <- read_tsv("../data/hpa/proteinatlas_v24.tsv") %>% janitor::clean_names() %>% 
  mutate(secretome_location = ifelse(is.na(secretome_location),"Not secreted",secretome_location))
# HPA tissue expression v23
hpa.tissue <- read_tsv("../data/hpa/rna_tissue_consensus.tsv") %>% janitor::clean_names()


# Load cleaned malaria data
#-   assays with QC warn in more than 70% of all assays
#-   samples with more than 70% below LOD
data.wide <- readRDS("../data/data_clean/Explore1536_tidy_wide.rds")
data.long <- readRDS("../data/data_clean/Explore1536_tidy_long.rds")

## Explore 1536 data set - MGH Covid-19 study, Filbin et al. 2021
covid_NPXdata <- read_delim("../data/MGH_OLINK_COVID/MGH_COVID_OLINK_NPX.txt",comment = "##")
mgh.covid.meta <- read_delim("../data/MGH_OLINK_COVID/MGH_COVID_Clinical_Info.txt", comment="##") %>% janitor::clean_names()
mgh.covid.meta.key <- read_excel("../data/MGH_OLINK_COVID/variable_descriptions.xlsx")

## load tropical fever cohort data
TF_SOFA <- readRDS("../data/metaData_clean/2021213_TF_DA_TROP_SOFAscores.rds") %>% filter(diagnose_clean!="P.falciparum")
TF.long <- readRDS("../data/data_clean/Explore1536_TF_tidy_long.rds")

## loding  MIP Cohort FACS data - Lautenbach et al. Cell Reports 2022

FACs_data <- read_delim("../../MalariaTravellers/data/TravellerCohort_FACS_log2cpu_long.csv")
FACS_meta <- read_delim("../../MalariaTravellers/data/TravellerCohort_SubjectTable.csv")

Set theme & colors

theme_set(theme_minimal(base_size = 6))

time3_col <- c("Acute" = "#C51B7D", 
               "D10" = "#E9A3C9",
               "M12" = "#4D9221")

sex2_col <- c(male = "#c5b8dc",
              female = "#b9d2b1")

endemic2_col <- c(primary_infected = "#998EC3",
                  previously_exposed = "#F1A340")
severe_5_col = c("1"="tomato",
                 "0"="grey80")

secretome_location_cols <- c("Secreted to blood" = "#FB8072",
                             "Intracellular and membrane" = "#8DD3C7",
                             "Secreted in other tissues" = "#B3DE69",
                             "Secreted to extracellular matrix" = "#80B1D3",
                             "Secreted in brain" = "#b9d2b1",#"#FCCDE5",
                             "Secreted to digestive system" = "#FDB462",
                             "Secreted - unknown location" = "#FFFF00",
                             "Secreted in male reproductive system" = sex2_col[[1]],#"#BEBADA",
                             "Secreted in female reproductive system" = sex2_col[[2]],
                             "Not secreted" = "#D9D9D9")

secretome_location_tissue_spec_cols <- c(secretome_location_cols,
                                         c("Not secreted - Tissue enriched" = "#88419d",
                                           "Not secreted - Tissue enhanced" = "#8c96c6",
                                           "Not secreted - Group enriched" = "#b3cde3",
                                           "Not secreted - Low tissue specificity" = "#edf8fb")
                                         )

SOFA_sub_col = colorRamp2(c(0,4), c("white","red"))

patient_kclust3 <- c('3' = "#92c5de", '2' = "#f4a582", '1' = "#ca0020")
patient_kclust3_lab <- c("mild"="#92c5de", "moderate"="#f4a582", "severe"="#ca0020")
patient_kclust3_lab_conv <- c("mild"="#92c5de", "moderate"="#f4a582", "severe"="#ca0020","convalescence" ="grey50")



SOFA_sub_col = colorRamp2(c(0,4), c("white","red"))

SOFA_total_col = colorRamp2(c(min(subjectTable$SOFA_total,na.rm = TRUE),
                              median(subjectTable$SOFA_total,na.rm = TRUE),
                              max(subjectTable$SOFA_total,na.rm = TRUE)),
                            c(brewer.pal(3,name="PuBu")))

## dimensinality reduction theme
my_dimred_theme <- theme_classic() + 
  theme(axis.text = element_blank(),
        axis.ticks = element_blank(),
        #text = element_text(size = 12),
        #legend.text = element_text(size = 10),
        legend.position = "right") 

## a4 pdf theme
theme_a4_pdf <- theme(axis.text.x = element_text(size=6),
                      axis.text.y = element_text(size=6),
                      axis.title.x = element_text(size=6),
                      axis.title.y = element_text(size=6),
                      ## legend
                      legend.key.size = unit(1, 'cm'), #change legend key size
                      legend.key.height = unit(0.25, 'cm'), #change legend key height
                      legend.key.width = unit(0.25, 'cm'), #change legend key width
                      legend.title = element_text(size=6), #change legend title font size
                      legend.text = element_text(size=6),
                      ## label
                      plot.title = element_blank(),
                      plot.subtitle =  element_blank(),
                      plot.caption =  element_blank(),
                      ## facet_grid
                      strip.text.x = element_text(size = 6,face="bold"),
                      #strip.text.y = element_text(size = 6),
                      strip.placement = "outside"
)

## patchwork panel a4 pdf theme
patchwork_panel_a4_pdf <- patchwork::plot_annotation(theme = theme(plot.title = element_text(size = 12),
                                                                   plot.tag = element_text(size = 16,face = 'bold')
),
tag_levels = 'A') 
asym_study_id <- c("2021004")

## 2013004 - Lib 1
## 2013007 - Lib 2
## 2013008 - Lib 3
## 2018002 - Lib 4

rhapsody_study_ids <- c("2013004","2013007","2013008","2018002")
#require(clusterProfiler)

#length(unique(data$UniProt)) ## 1463
mapping_uniprot_ensembl <- bitr(unique(data$UniProt), 
                                fromType="UNIPROT",
                                toType=c("SYMBOL", "ENSEMBL","ENTREZID"), 
                                OrgDb="org.Hs.eg.db") %>% 
  dplyr::rename(UniProt = UNIPROT,
                Symbol = SYMBOL,
                Ensembl = ENSEMBL,
                Entrez = ENTREZID) %>%
  inner_join(data %>% dplyr::select(Assay,UniProt) %>% dplyr::distinct(),by="UniProt")

#write_delim(mapping_uniprot_ensembl, "../../2022_Explore1536FarnertLab/data/Mapping_Explore_UniProt2Ensembl.txt")

Figure 1

Plasma proteomic perturbation during clinical malaria - Cohort characteristics

fig1.list <- list()

Figure 1B

(fig1.list[["general_sex_age_dist"]] <- subjectTable %>% 
    ggplot(aes(x=age, fill=sex)) +
    geom_density(alpha=.6) +
    #theme_classic() +
    theme(axis.text = element_text(size=6), 
          axis.title = element_text(size=6), 
          axis.ticks.x = element_blank()) + 
    scale_fill_manual(values=sex2_col) +
    scale_color_manual(values=sex2_col) +
    
    labs(fill="Sex",
         x="age [years]",
         y="density")
)

Figure 1C

(fig1.list[["timepoint_sex_perc"]] <-sampleTable_simple %>% 
    inner_join(subjectTable,by="study_id") %>% 
    group_by(Time,sex) %>% 
    tally() %>% 
    group_by(Time) %>% 
    dplyr::mutate(percent=n/sum(n)) %>% 
    ggplot(aes(x=Time,y=n,fill=sex)) +
    geom_bar(stat="identity", position ="fill") +
    geom_text(aes(label=paste0(sprintf("%1.1f", percent*100),"%")),
              position=position_fill(vjust=0.5), colour="white", size =1.5) +
    scale_y_continuous(labels = scales::percent,expand = c(0,.01)) + 
    #theme_minimal() +
    theme(legend.position = "top",
          axis.ticks.x = element_blank()) + 
    scale_fill_manual(values=sex2_col) +
    labs(fill=NULL,
         x=NULL,
         y="Percentage")
)

Figure 1D

(fig1.list[["timepoint_exposure"]] <- sampleTable_simple %>% 
    inner_join(subjectTable,by="study_id") %>% 
    group_by(Time,endemic) %>% 
    tally() %>% 
    group_by(Time) %>% 
    dplyr::mutate(percent=n/sum(n)) %>% 
  mutate(endemic = factor(endemic, levels=c("primary_infected","previously_exposed"))) %>% 
    ggplot(aes(x=Time,y=n,fill=endemic)) +
    geom_bar(stat="identity", position ="fill") +
    geom_text(aes(label=paste0(sprintf("%1.1f", percent*100),"%")),
              position=position_fill(vjust=0.5), colour="white", size =1.5) +
    scale_y_continuous(labels = scales::percent,expand = c(0,.01)) + 
    #theme_minimal() +
    theme(legend.position = "top",
          axis.ticks.x = element_blank()) + 
    scale_fill_manual(values=endemic2_col,labels=c("primary_infected"="primary infected","previously_exposed"="previously exposed")) +
    labs(fill=NULL,
         x=NULL,
         y="Percentage")
)

Figure 1E

df <- data.wide %>% 
  inner_join(sampleTable_simple %>% 
               transmute(sample_id),
             by="sample_id") %>% 
  column_to_rownames("sample_id")

## PC calculation
pcaRes <- stats::prcomp(df,center = TRUE, scale. = TRUE)
varExp <- round(pcaRes$sdev^2 / sum(pcaRes$sdev^2) * 100)
pcaDF <- data.frame(PC1 = pcaRes$x[, 1],
                    PC2 = pcaRes$x[, 2]) %>% 
  rownames_to_column("sample_id") 

## Prep for plotting
data4plot <- pcaDF %>% 
  dplyr::inner_join(sampleTable_simple, by="sample_id")


(pca_fig1 <- data4plot %>% 
    ggplot(mapping = aes(x = PC1, y = PC2, color = Time,fill=NULL, label = NULL)) +
    geom_point(alpha = 0.9, size = 1) +
    ggplot2::scale_color_manual(values= time3_col) +
    labs(x = paste0("PC1 (",  varExp[1], " %)"),
         y = paste0("PC2 (",  varExp[2], " %)")) +
    theme_minimal()  +
    theme(legend.title = element_text(size = 6), 
          legend.text = element_text(size = 6)))

Figure 1F

## nest data
data_nested <- data.long %>% 
  inner_join(sampleTable_simple, by="sample_id") %>% 
  group_by(UniProt,Assay) %>% 
  nest()
## nest data
data_nested <- data.long %>% 
  inner_join(sampleTable_simple, by="sample_id") %>% 
  left_join(subjectTable %>% transmute(study_id, 
                                       exposure = factor(endemic, levels=c("primary_infected","previously_exposed"))),
            by="study_id") %>% 
  group_by(UniProt,Assay) %>% 
  nest()

lme_res <- data_nested %>% 
  mutate(lme.res.simple = purrr::map(data, ~ lmerTest::lmer(NPX ~ Time + exposure + (1|study_id), REML = F,
                                                            control = lme4::lmerControl(check.conv.singular = "ignore"),
                                           data = .x %>% dplyr::filter(Time!="D10"))),
         lme.res.complex = purrr::map(data, ~ lmerTest::lmer(NPX ~ Time * exposure + (1|study_id), REML = F,
                                                             control = lme4::lmerControl(check.conv.singular = "ignore"),
                                           data = .x %>% dplyr::filter(Time!="D10"))),
         lme.simple.tidy = purrr::map(lme.res.simple, ~ broom.mixed::tidy(.,)),
         lme.complex.tidy = purrr::map(lme.res.complex, ~ broom.mixed::tidy(.)),

         posthoc.time = purrr::map(lme.res.simple, ~ summary(contrast(emmeans(., ~ Time), method = "pairwise")) %>% tibble()),
         posthoc.time_exposure = purrr::map(lme.res.complex, ~ summary(contrast(emmeans(., ~ Time * exposure), method = "pairwise")) %>% tibble())
         )
  • finding better model
## compare simple (without interaction) with complex model (interaction)
bic_aic_res <- lme_res %>% 
  mutate(simple_glance = purrr::map(lme.res.simple, ~(broom::glance(.))),
         complex_glance = purrr::map(lme.res.complex, ~(broom::glance(.)))) %>% 
  unnest(cols = c(simple_glance,complex_glance),names_sep = ".") %>% 
  dplyr::select(Assay, contains("AIC"),contains("BIC"))

df_better_model <- bic_aic_res %>% 
  pivot_longer(cols=c(-UniProt,-Assay)) %>% 
  separate(name, into=c("model","eval"),sep = "\\.",remove = T) %>% 
  pivot_wider(names_from = model, values_from = value) %>% 
  mutate(simple_better = simple_glance < complex_glance,
         simple_delta = simple_glance-complex_glance,
         better_model = case_when(abs(simple_delta)>6 ~ "complex",
                                  .default = "simple"))
df_better_model %>% 
  group_by(eval) %>% 
  count(better_model) %>% 
  ggplot(aes(x=better_model, y=n)) +
  geom_col() +
      geom_text(aes(label=n),size=2,nudge_y = 50) + 
  facet_wrap(~eval)

df_better_model %>% filter(eval=="BIC",
                           better_model=="complex") 
## # A tibble: 14 × 8
## # Groups:   UniProt, Assay [14]
##    UniProt Assay   eval  simple_glance complex_glance simple_better simple_delta
##    <chr>   <chr>   <chr>         <dbl>          <dbl> <lgl>                <dbl>
##  1 Q9Y275  TNFSF1… BIC           276.           267.  FALSE                 9.66
##  2 P10586  PTPRF   BIC           153.           146.  FALSE                 7.56
##  3 P05107  ITGB2   BIC           148.           141.  FALSE                 6.98
##  4 Q9HAN9  NMNAT1  BIC           401.           394.  FALSE                 6.73
##  5 P50135  HNMT    BIC           340.           332.  FALSE                 8.39
##  6 Q9UL46  PSME2   BIC           199.           192.  FALSE                 6.96
##  7 P04179  SOD2    BIC           328.           319.  FALSE                 9.55
##  8 P00352  ALDH1A1 BIC           302.           290.  FALSE                11.6 
##  9 Q9P0V8  SLAMF8  BIC           308.           301.  FALSE                 6.78
## 10 Q16772  GSTA3   BIC           350.           341.  FALSE                 8.69
## 11 Q86SF2  GALNT7  BIC            74.3           68.0 FALSE                 6.33
## 12 Q96I15  SCLY    BIC           280.           273.  FALSE                 6.67
## 13 Q00796  SORD    BIC           401.           391.  FALSE                10.3 
## 14 Q7Z4W1  DCXR    BIC           300.           289.  FALSE                11.3 
## # ℹ 1 more variable: better_model <chr>
lme_res_padj <- lme_res %>% 
  unnest(cols="posthoc.time") %>% 
  filter(contrast=="Acute - M12") %>% 
  ungroup() %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
                  FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
  arrange(p.adj)
assay_better_complex_model <- df_better_model %>% filter(eval=="BIC",
                                                         better_model=="complex") %>% pull(Assay)

plot(euler(
  list("acute_m12" = lme_res_padj %>% filter(FDR==T) %>% pull(Assay),
       "bic_complex_better" = assay_better_complex_model)),#df_better_model %>% filter(eval=="BIC", better_model=="complex") %>% pull(Assay))),
  
        fills = c("#C51B7D",
                  "white"),
       quantities = TRUE,
       lty = 1,#1:3,
       fontsize=2,
       labels = list(fontsize=7),
       shape = "ellipse",adjust_labels = T)

lme_res_padj %>% 
  transmute(Assay, estimate,p.adj) %>% 
  filter(Assay %in% assay_better_complex_model) %>% 
  arrange(-abs(estimate))
## # A tibble: 14 × 3
##    Assay    estimate    p.adj
##    <chr>       <dbl>    <dbl>
##  1 SLAMF8     2.48   4.64e-16
##  2 HNMT       1.42   2.76e- 7
##  3 NMNAT1     1.18   1.77e- 3
##  4 ALDH1A1    1.13   3.00e- 6
##  5 TNFSF13B   1.04   1.30e- 6
##  6 GSTA3      1.03   5.20e- 4
##  7 SOD2       0.920  5.69e- 4
##  8 SCLY       0.905  1.54e- 5
##  9 PSME2      0.814  6.65e- 8
## 10 DCXR       0.637  3.36e- 3
## 11 ITGB2      0.623  2.43e- 8
## 12 SORD       0.391  3.10e- 1
## 13 GALNT7    -0.0573 4.89e- 1
## 14 PTPRF     -0.0129 9.28e- 1
dap.res <- lme_res_padj %>% 
  dplyr::rename(logFC = estimate) %>% 
  mutate(direction = ifelse(logFC<0,"down","up"))  %>% 
  dplyr::select(-c(lme.res.simple,lme.res.complex,lme.complex.tidy)) %>% 
  ## remove assays that would require a complex model
   filter(!Assay %in% assay_better_complex_model)
(dap.acute.volcano <- dap.res %>% 
   ggplot(aes(x=logFC, y=-log10(p.adj), color=FDR)) +
   geom_point(alpha=0.7,size=.5, shape=16) +
   theme_minimal() +
   ggrepel::geom_text_repel(data = . %>% filter(FDR ==TRUE, abs(logFC) >1.5),
                            aes(label = Assay), color="black",
                            force        = 0.5,
                            direction    = "both",
                            segment.size = 0.2,
                            segment.alpha=.1,
                            show.legend = F,
                            size=1,
                            max.overlaps = 16,
                            box.padding = unit(0.2, "lines"),
                            point.padding = unit(0.5, "lines"),
                            segment.color = 'grey50') +
   
   geom_vline(xintercept = c(-1, 1), linetype = "dotted", size = .5) +
   geom_hline(yintercept = -log10(0.01), linetype = "dotted", size = .5) + 
   #scale_x_continuous(breaks=c(-5.0,-2.5,-1.0,0.0,1.0,2.5,5.0,7.5),limits = c(-5,7.5)) +
      scale_x_continuous(breaks=c(-4.0,-3.0,-2.0,-1.0,0.0,1.0,2.0,3.0,4.0,5.0,6.0),limits = c(-4,6)) +

   geom_segment(aes(x = 1.1, y = 21, xend = 4, yend = 21), color=time3_col[[1]], #y=16.5
                arrow = arrow(length = unit(0.2, "cm"))) +
   annotate("text",x=2.6, y=22.5, size=2, label="High abundant\nin acute malaria") + #y=17.6
   
   geom_segment(aes(x = -1.1, y = 21, xend = -4, yend = 21),color=time3_col[[1]],
                arrow = arrow(length = unit(0.2, "cm"))) +
   annotate("text",x=-2.6, y=22.5, size=2, label="Low abundant\nin acute malaria") + #y=17.1
   
   labs(x="Estimated difference (NPX) at acute compared to convalescence",
        y="-log10(adj. p-value)") +
   theme(legend.position = "none",
         text = element_text(size=6)) +
   scale_color_manual(values= c(time3_col[[3]],time3_col[[1]])))

Figure 1G

hm.input <- data.wide %>% 
  inner_join(sampleTable_simple %>% dplyr::select(DAid,study_id, sample_id, Time),by="sample_id") %>% 
  dplyr::filter(Time=="Acute")

top25 <- dap.res %>% dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>%
  mutate(up_down = ifelse(logFC>0,"up","down")) %>% 
  dplyr::group_by(up_down) %>% 
  slice_head(n=25)

top25.split <- top25 %>% column_to_rownames("Assay") %>% transmute(direction = factor(direction, levels = c("up","down"), labels = c("high","low")))

norm.df <- hm.input %>% column_to_rownames("sample_id") %>% 
  dplyr::select(-c(DAid,Time,study_id)) %>% 
  dplyr::select(c(top25$Assay)) %>% 
  t() %>% scale()

## == ComplexHeatmap == ##
(acute.npx.top25.hm <- norm.df %>% 
    scale() %>% 
    Heatmap(name="scaled\nNPX",
            clustering_distance_columns = "spearman",
            clustering_method_columns="ward.D2",
            
            top_annotation = HeatmapAnnotation(df = data.frame(sample_id = colnames(.)) %>%
                                                 separate(sample_id, into = c("study_id","Time"),sep="\\|") %>% 
                                                 left_join(subjectTable %>% transmute(study_id,
                                                                                      endemic = factor(case_when(endemic=="primary_infected"~"primary",
                                                                                                          endemic=="previously_exposed"~"previously",
                                                                                                          .default=NA),levels=c("primary","previously")),
                                                                                      severe_5 = ifelse(severe_5==1,"yes","no"))) %>%
                                                 dplyr::select(-study_id,-Time),
                                               simple_anno_size = unit(2, "mm"),
                                               show_annotation_name = F,
                                               annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                                              title_gp = gpar(fontsize = 6),
                                                                              legend_height = unit(3, "mm"), 
                                                                              grid_width = unit(3, "mm")),
                                               show_legend = T,
                                               annotation_label = list(severe_5 = "Severe malaria\n(WHO)",
                                                                       endemic = "exposure"),
                                        col = list(endemic =  c("previously"= "#F1A340","primary"= "#998EC3"),#endemic2_col,
                                                   severe_5 = c("yes"="tomato","no"="grey80")),#severe_5_col),
                                        which="column"),
            
            show_column_names = F,
            column_names_gp = gpar(fontsize = 8),
            show_column_dend = TRUE,
            cluster_columns = TRUE,
            column_dend_reorder = TRUE,
            row_dend_reorder=1-rowSums(abs(norm.df)),
            cluster_row_slices = FALSE,
            row_dend_width = unit(0.5, "cm"), 
            column_dend_height = unit(0.5, "cm"), 
            raster_resize_mat = mean,
            row_title_gp = gpar(fontsize=6),
            show_row_names = TRUE,
            row_split = top25.split,
            row_gap = unit(0.05,"cm"),
            row_names_gp = gpar(fontsize = 6),
            heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                        title_gp = gpar(fontsize = 6),
                                        legend_height = unit(3, "mm"), 
                                        grid_width = unit(3, "mm")),
            height = ncol(.)*unit(1.4, "mm"),
            width = ncol(.)*unit(.14,"mm")
    ))

Figure 1H

top10up <- dap.res %>% dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>%
  mutate(up_down = ifelse(logFC>0,"up","down")) %>% 
  filter(up_down=="up") %>% 
  head(n=10) %>%
  pull(Assay)

(violin_malaria_top10 <- data.long %>% 
   inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),
              by="sample_id") %>% 
   dplyr::filter(Assay %in% c(top10up)) %>% 
   mutate(Assay = factor(Assay, levels = top10up)) %>% 
   
   ggplot(aes(x=Time, y=NPX, color=Time,fill=Time)) + 
   geom_line(aes(group=study_id), color="grey",alpha=.6,size=.2)+
   geom_violin(trim = F,alpha=.2,lwd=.25) +
   geom_boxplot(alpha=1,width=0.25,color="black",outlier.size = 0.5, fatten = 1,lwd=.25,show.legend = F) +
   facet_wrap(~Assay,ncol = 5,scales = "free_y") +
   theme_minimal() +
   labs(x="") +
   theme(axis.text.x = element_text(size=6),
         legend.position = "none") +
   scale_color_manual(values=time3_col) +
   scale_fill_manual(values=time3_col))

Figure 1I

top10down <- dap.res %>% dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>%
  mutate(up_down = ifelse(logFC>0,"up","down")) %>% 
  filter(up_down=="down") %>% 
  head(n=10) %>%
  pull(Assay)

(violin_malaria_top10_down <- data.long %>% 
   inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),
              by="sample_id") %>% 
   dplyr::filter(Assay %in% c(top10down)) %>% 
   mutate(Assay = factor(Assay, levels = top10down)) %>% 
    ggplot(aes(x=Time, y=NPX, color=Time,fill=Time)) + 
    geom_line(aes(group=study_id), color="grey",alpha=.6,size=.2)+
    geom_violin(trim = F,alpha=.2,lwd=.25) +
    geom_boxplot(alpha=1,width=0.25,color="black",outlier.size = 0.5, fatten = 1,lwd=.25,show.legend = F) +
    facet_wrap(~Assay,ncol = 5,scales = "free_y") +
    theme_minimal() +
    labs(x="") +
    theme(axis.text.x = element_text(size=6),
          legend.position = "none") +
    scale_color_manual(values=time3_col) +
    scale_fill_manual(values=time3_col))

Supplementary Table S1

##gtsummary
library(gtsummary)
subjectTable %>% 
  mutate(years_since_endemic = case_when(endemic=="primary"~NA,
                                         .default = years_since_endemic),
         
         SOFA_total = as.numeric(SOFA_total),
         endemic = str_replace(endemic,"_"," "),
         severe_5 = case_when(severe_5==1 ~ "severe",.default = "non-severe")) %>% 
  tbl_summary(include = c(sex, age, endemic, years_since_endemic, diff_acuteSample_spt_current.abs, inf_rbc_max, severe_5,SOFA_total),
              
              statistic = list(all_continuous() ~ "{median} ({min}-{max})",
                               all_categorical() ~ "{n} / {N} ({p}%)"
              ),
             # digits = all_continuous() ~ 2,
             digits = c(age ~ 0,
                        years_since_endemic ~ 0,
                        diff_acuteSample_spt_current.abs ~ 0,
                        inf_rbc_max ~ 2),
              label = c(endemic ~ "Previous malaria exposure",
                        age ~ "Age",
                        sex ~"Sex",
                        years_since_endemic ~ "Years since living in endemic area",
                        inf_rbc_max ~ "Parasitemia [%]",
                        SOFA_total ~ "SOFA scale",
                        diff_acuteSample_spt_current.abs ~ "Days since symptom onset",
                        severe_5 = "Severe malaria according to WHO criteria\n(ref WHO Guidelines for the treatment of Malaria , 3rd edition, 2015)"),
              missing = "no"
  ) %>% 
  add_n() %>% # add column with total number of non-missing observations
  modify_header(label = "**Variable**") %>% # update the column header
  bold_labels() 
Variable N N = 721
Sex 72
    female 17 / 72 (24%)
    male 55 / 72 (76%)
Age 72 39 (20-63)
Previous malaria exposure 72
    previously exposed 48 / 72 (67%)
    primary infected 24 / 72 (33%)
Years since living in endemic area 47 10 (0-33)
Days since symptom onset 69 4 (0-27)
Parasitemia [%] 72 0.80 (0.01-8.00)
Severe malaria according to WHO criteria (ref WHO Guidelines for the treatment of Malaria , 3rd edition, 2015) 72
    non-severe 62 / 72 (86%)
    severe 10 / 72 (14%)
SOFA scale 72
    0 1 / 72 (1.4%)
    1 7 / 72 (9.7%)
    2 19 / 72 (26%)
    3 16 / 72 (22%)
    4 13 / 72 (18%)
    5 8 / 72 (11%)
    6 5 / 72 (6.9%)
    9 2 / 72 (2.8%)
    12 1 / 72 (1.4%)
1 n / N (%); Median (Minimum-Maximum)

Supplementary Table S2

daps.out <- lme_res_padj %>% 
  transmute(UniProt, 
            Assay,
            estimate,
            contrast, 
            SE,
            CI = 1.96*SE,
            df,
            t.ratio,
            p.value, 
            p.adj,
            preffered_model = case_when(Assay %in% assay_better_complex_model ~ "complex",
                                        .default = "simple"))
#daps.out%>%  write_tsv(paste0(result.dir,"Supplementary_TableS2_DifferentiallyAbundantProteins.tsv"))
daps.out %>% head()
## # A tibble: 6 × 11
##   UniProt Assay    estimate contrast    SE    CI    df t.ratio  p.value    p.adj
##   <chr>   <chr>       <dbl> <chr>    <dbl> <dbl> <dbl>   <dbl>    <dbl>    <dbl>
## 1 P28908  TNFRSF8      2.95 Acute -… 0.194 0.379  66.3    15.2 2.34e-23 3.33e-20
## 2 P22301  IL10         6.62 Acute -… 0.455 0.892  66.3    14.5 2.65e-22 1.38e-19
## 3 Q07325  CXCL9        4.33 Acute -… 0.293 0.574  62.9    14.8 3.86e-22 1.38e-19
## 4 P04233  CD74         2.20 Acute -… 0.134 0.263  52.0    16.4 3.41e-22 1.38e-19
## 5 P20333  TNFRSF1B     2.66 Acute -… 0.185 0.363  66.3    14.4 5.00e-22 1.43e-19
## 6 P19320  VCAM1        1.48 Acute -… 0.105 0.207  66.3    14.0 1.78e-21 4.22e-19
## # ℹ 1 more variable: preffered_model <chr>

Supplementary Figure 1

Figure S1A

tmp <- data.long %>% 
  distinct(sample_id) 
hm_mat <- tmp %>% 
  separate(sample_id, into = c("study_id","Time"),sep = "\\|",remove = T) %>% 
   mutate(Time = factor(Time, levels=c("Acute","D10","M12")),
          dummy = Time) %>% 
  
  group_by(study_id) %>% 
  mutate(n = n()) %>% 
  arrange(-n) %>% 
  ungroup() %>% 
  
  pivot_wider(names_from = Time, values_from = dummy) %>% 
  dplyr::select(-n) %>% 
  column_to_rownames("study_id") %>% 
  relocate(Acute,D10,M12) %>% 
  t() 

(sample_overlap_hm <- hm_mat %>% 
  Heatmap(row_names_gp = gpar(fontsize=6),
          show_column_names = F,
          na_col = "white",
          column_title_gp = gpar(fontsize=6),
          row_names_side = "left",
          column_names_gp = gpar(fontsize=6),
          column_names_rot = 45,
          show_heatmap_legend = F,
          column_split = data.frame(study_id = colnames(hm_mat)) %>% 
            left_join(subjectTable %>% 
                        transmute(study_id, endemic) %>% 
                        bind_rows(
                          tibble(study_id = c("2014003","2012PT12"),
                                 endemic = c("primary_infected","primary_infected")))) %>%  
            transmute(endemic= factor(endemic, levels=c("primary_infected","previously_exposed"), labels= c("primary infected","previously exposed"))),
          row_title_gp = gpar(fontsize=6),
          
          rect_gp = gpar(col = "white", lwd = .5),
          width = ncol(.)*unit(1, "mm"), 
          height = nrow(.)*unit(2, "mm"),
          #height = ncol(.)*unit(1.4, "mm"),
          #  width = ncol(.)*unit(.5,"mm"),
          border_gp = gpar(col = "black", lty = .9),
          col =  time3_col,
          top_annotation = HeatmapAnnotation(df = data.frame(study_id = colnames(.)) %>% 
                                               left_join(subjectTable %>% 
                                                           transmute(study_id, endemic) %>% 
                                                           bind_rows(
                                                             tibble(study_id = c("2014003","2012PT12"),
                                                                    endemic = c("primary_infected","primary_infected"))
                                                             )) %>% 
                                                           dplyr::select(-study_id),
                                                         simple_anno_size = unit(3, "mm"),
                                                         show_annotation_name = F,
                                                         show_legend = F,
                                                         col = list(endemic =  endemic2_col),
                                                         which="column"))
)

Figure S1B

(acute_exposure_volcano <- lme_res %>% 
  unnest(cols=posthoc.time_exposure) %>% 
  filter(contrast %in%c("Acute primary_infected - M12 primary_infected",
                    "Acute previously_exposed - M12 previously_exposed")) %>% 
  ungroup() %>% 
  group_by(contrast) %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
         FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
  arrange(p.adj) %>% 
  transmute(Assay,contrast, estimate,SE,df,t.ratio, p.value, p.adj, FDR,
            color = case_when(FDR==T & contrast=="Acute primary_infected - M12 primary_infected" ~ "primary_infected",
                              FDR==T & contrast=="Acute previously_exposed - M12 previously_exposed" ~ "previously_exposed",
                              .default = NA
                              ),
            contrast = factor(contrast, levels=c("Acute primary_infected - M12 primary_infected",
                                                 "Acute previously_exposed - M12 previously_exposed")),
            label_4_complex_better = case_when(Assay %in% assay_better_complex_model & contrast=="Acute primary_infected - M12 primary_infected" ~ Assay,
                                               .default = NA)) %>% 
  
  ggplot(aes(y=fct_reorder(Assay, estimate), x=estimate, color=color)) +
 
  scale_color_manual(values=endemic2_col, na.value = "grey",breaks = c("primary_infected","previously_exposed")) +
  labs(color=NULL,
       x="Estimated difference +- 95% CI at acute for\nprimary infected and previously exposed individuals\ncompared to M12",#"Estimated difference (NPX) at acute compared to healthy-state at M12",
       y="ranked proteins") +
  geom_errorbar(aes(xmin=estimate - 1.96*SE, 
                    xmax=estimate + 1.96*SE),
                linewidth=.2,    # Thinner lines
                width=.2,
                alpha=.1) +
    geom_point(alpha=0.7,size=.5, shape=16) +
   geom_text_repel(aes(label=label_4_complex_better),#ifelse(Assay %in% assay_better_complex_model & color=="primay_infected",Assay,NA)),
                    show.legend = F,
                   color="black",
                    vjust = .5,
                    hjust = 1,
                    nudge_x = .75,
                    direction = "y",
                    size=1,
                   #label.size = .1,
                    segment.size = 0.2,
                            segment.alpha=.1,
                    max.overlaps = 16) +
  geom_vline(xintercept = 0, lty=2, alpha=.6) +
  theme_minimal())

lme_res_expo <- lme_res %>% 
  unnest(cols="posthoc.time_exposure") %>% 
  filter(contrast=="Acute primary_infected - Acute previously_exposed") %>% 
  ungroup() %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
                  FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
  filter(FDR==T) %>% 
  arrange(-estimate) 

assays_significant_different_at_acute_exp <- lme_res_expo %>% 
  pull(Assay)

Figure S1C

library(eulerr)

plot(euler(list("acute" = lme_res_padj %>% filter(FDR==T) %>% pull(Assay),
                  "exposure"= lme_res_expo %>% filter(FDR==T) %>% pull(Assay))),# assays_significant_different_at_acute_exp)),#lme_res_expo %>% filter(FDR==T) %>% pull(Assay))),
        fills = c("#C51B7D",
                  "white"),
       quantities = TRUE,
       lty = 1,#1:3,
       fontsize=1,
       labels = list(fontsize=5),
       shape = "ellipse",adjust_labels = T)

acut_exposure_intersect <- intersect(assays_significant_different_at_acute_exp,#lme_res_expo %>% filter(FDR==T) %>% pull(Assay),
                                     lme_res_padj %>% filter(FDR==T) %>% pull(Assay))

Figure S1D

df <- lme_res %>% 
  filter(Assay %in% assays_significant_different_at_acute_exp) %>% 
  mutate(Assay = factor(Assay, levels=assays_significant_different_at_acute_exp)) %>% 
  unnest(cols=posthoc.time_exposure) %>% 
  filter(contrast %in%c("Acute primary_infected - M12 primary_infected",
                        "Acute previously_exposed - M12 previously_exposed")) %>% 
  ungroup() %>% 
  mutate(color = case_when(contrast=="Acute primary_infected - M12 primary_infected" ~ "primary_infected",
                           contrast=="Acute previously_exposed - M12 previously_exposed" ~ "previously_exposed",
                              .default = NA
                              )) %>%
 # rownames_to_column("rownumbers") %>% 
  #filter(Assay%in%c("CXCL10","IFNG","CXCL9","TNFSF13B")) %>% 
  dplyr::select(-(lme.res.simple:posthoc.time)) 
require(ggtext)
(acute_exposure_significant <- df %>% 
    mutate(x.label = paste("<span style = 'color: ",
                         ifelse(Assay %in% acut_exposure_intersect , "pink", "black"),
                         ";'>",
                         Assay,
                         "</span>", sep = ""),
         x.label = fct_reorder(x.label, as.character(Assay))) %>%
  ggplot(aes(x=x.label, y=estimate, color=color)) +
  geom_point(shape=16,size=.5) +
  scale_color_manual(values = endemic2_col, breaks = c("primary_infected","previously_exposed")) +

  geom_hline(yintercept = 0, lty=2, alpha=.3) +
 #  ggrepel::geom_text_repel(show.legend = F, color="black") +
  geom_errorbar(aes(ymin=estimate - 1.96*SE, 
                    ymax=estimate + 1.96*SE),
                linewidth=.2,    # Thinner lines
                width=.2,
                alpha=.5) +
  labs(x=NULL,
       color = NULL,
       y="Estimated difference +- 95% CI at acute for\nprimary infected and previously exposed individuals\ncompared to M12\n") +
      theme(axis.text.x = element_markdown(angle = 90, hjust = 1,vjust=0.5, size=6),
            legend.position = "top")
)

Supplementary Figure 2

related to main Figure 2

Figure S2A

supplementary_covariates.res <- data.long %>% 
  inner_join(sampleTable_simple, by="sample_id") %>% 
  inner_join(subjectTable, by="study_id") %>% 
  filter(Time != "D10") %>% 
  mutate(Time = factor(Time, levels=c("Acute","M12"))) %>% 
  group_by(Assay) %>% 
  nest() %>% 
  mutate(lme.res = purrr::map(data, ~ lmerTest::lmer(NPX ~ Time + year_inclusion + sex + age + endemic + inf_rbc_max + (1|study_id), REML = F,
                                           data = .)),
         lme.tidy = purrr::map(lme.res, ~ broom.mixed::tidy(.)))

supplementary_covariates.res_ <- supplementary_covariates.res %>% 
  unnest(cols = lme.tidy) %>% 
  filter(effect =="fixed", 
         term!="(Intercept)") %>% 
  #filter(term != "Residuals") %>% 
  mutate(term = case_when(term=="sexmale"~"sex",
                          term=="endemicprimary_infected"~"endemic",
                          term=="TimeM12"~"Time",
                          .default = term)) %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr")
  ) %>%
  mutate(term.col = case_when(p.adj > 0.01 ~ NA,
                              p.adj <= 0.01 ~ term))

cov.colors <- c("Time" = time3_col[[1]],setNames(brewer.pal(7,"Dark2")[c(1:3,5:8)], c("sex","endemic","age","year_inclusion","inf_rbc_max")))

counts.fdr <- supplementary_covariates.res_ %>% 
  filter(p.adj <= 0.01) %>% 
  group_by(term) %>% 
  count(sort = T)

(data.aov.plot <- supplementary_covariates.res_ %>% 
    mutate(term = factor(term, levels=counts.fdr$term)) %>% 
    ggplot(aes(x=term, y= -log10(p.adj))) + 
    geom_jitter(aes(color=term.col), show.legend = F,size=.25,alpha=.7,shape=16) +
    ggrepel::geom_text_repel(data= . %>% group_by(term) %>% slice_max(n=5,order_by = -log10(p.adj)), 
                             aes(label=Assay), 
                             show.legend = F,force = .5, nudge_y = .25,
                             segment.size=0.2,
                            segment.alpha=.1,
                             size=1,
                             max.overlaps = 15, color="gray45") +
    geom_hline(yintercept=-log10(0.01), 
               linetype = 3) +
    scale_color_manual(values = cov.colors) +
    
    geom_text(data=counts.fdr,aes(x=term, y=-1.2, label=n, color=term), show.legend = F) +
    scale_x_discrete(labels=c("age" = "Age",
                              "year_inclusion" = "Year\nof\nsampling",
                              "sex" = "Sex",
                              "endemic" = "Previous\nexposure",
                              "inf_rbc_max" = "Parasitemia",
                              "Time" = "Infection\n(Acute vs convalescence)")) +
    theme_minimal() +
    labs(x=NULL, 
         color=NULL) +
    theme())

Figure S2B

n2show <- 3
(anova.sex.plot <- supplementary_covariates.res_ %>%
    filter(term=="sex") %>%
    arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    ggplot(aes(x=Time, y=NPX, fill=as.character(sex))) +
    geom_boxplot( fatten = 1,lwd=.25,outlier.size = 0.5) +
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(x=NULL,
         fill="Sex") +
    scale_fill_manual(values = sex2_col))

(anova.endemic.plot <- supplementary_covariates.res_ %>%
    filter(term=="endemic") %>%
    arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    ggplot(aes(x=Time, y=NPX, fill=as.character(endemic))) +
    geom_boxplot(fatten = 1,lwd=.25,outlier.size = 0.5) +
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(x=NULL,
         fill="Previous exposure") +
    scale_fill_manual(values = endemic2_col))

(anova.year_inclusion.plot <- supplementary_covariates.res_ %>%
    filter(term=="year_inclusion") %>% arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    ggplot(aes(x=as.numeric(year_inclusion),y=NPX,color=Time)) +
    geom_point(size=.5) +
    geom_smooth(linewidth=0.4,
                show.legend = F) +
    scale_x_continuous(limits = c(2011,2021),breaks = c(2011,2016,2021)) + 
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(x="Year of inclusion",
      color="Sample time point") +
    scale_color_manual(values = time3_col))

(anova.age.plot <- supplementary_covariates.res_ %>%
    filter(term=="age") %>% arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    ggplot(aes(x=as.numeric(age),y=NPX,color=Time)) +
    geom_point(size=.5) +
    geom_smooth(linewidth=0.4,
                show.legend = F) +
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(title="",
         x="Years",
         color="Age") + 
    scale_color_manual(values = time3_col)
)

(anova.inf_rbc_max.plot <- supplementary_covariates.res_ %>%
    filter(term=="inf_rbc_max") %>% arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    filter(Time=="Acute") %>% 
    ggplot(aes(x=as.numeric(inf_rbc_max),y=NPX,color=as.numeric(inf_rbc_max))) +
    geom_point(size=.5) +
    geom_smooth(aes(color=..x..),
                linewidth=0.4,
                show.legend = F) +
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(title="",
         x="Parasitemia, infected erythrocytes [%]",
         color="Parasitemia [%]") + 
    scale_color_gradient(low="grey",high="darkred")
  #scale_color_manual(values = time3_col)
)

(anova.panel <- (anova.inf_rbc_max.plot / 
                   anova.endemic.plot /
                   anova.year_inclusion.plot / 
                   anova.sex.plot/
                   anova.age.plot))

Figure S2C

lme_res.d10 <- data_nested %>% 
  mutate(lme.res = purrr::map(data, ~ lmerTest::lmer(NPX ~ Time + exposure + (1|study_id), REML = F,
                                           control = lme4::lmerControl(check.conv.singular = "ignore"),
                                           data = .x %>% dplyr::filter(Time!="Acute"))),
         #lme.tidy = purrr::map(lme.res, ~ broom.mixed::tidy(.)),
         posthoc.time = purrr::map(lme.res, ~ summary(contrast(emmeans(., ~ Time), method = "pairwise")) %>% tibble())#,
         #posthoc.time_exposure = purrr::map(lme.res, ~ summary(contrast(emmeans(., ~ Time * exposure), method = "pairwise")) %>% tibble())
         )

lme_res.d10_padj <- lme_res.d10 %>% 
  unnest(cols="posthoc.time") %>% 
  filter(contrast=="D10 - M12") %>% 
  #filter(contrast=="Acute primary_infected - Acute previously_exposed") %>% 
  ungroup() %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
         FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
  #   dplyr::rename(logFC = estimate) %>% 
  arrange(p.adj)
acut_d10_list <- list("Acute"=c(lme_res_padj %>% filter(FDR==TRUE, estimate>1) %>% pull(Assay)),
                      "D10" = c(lme_res.d10_padj %>% filter(FDR==TRUE, estimate>1) %>% pull(Assay)))

## venn plot with overlapp numbers
(venn.DAP.acute.d10 <- ggvenn::ggvenn(acut_d10_list,
                                      show_percentage = F,
                                      fill_color = as.character(time3_col[c(1,2)]), 
                                      stroke_size = 0.5,
                                      set_name_size = 2,
                                      text_size = 2,
                                      auto_scale = F,
                                      show_elements = F) +
    theme(plot.title = element_text(hjust = 0.5),
          plot.subtitle = element_text(hjust = 0.5),
          text = element_text(size=6),
          strip.text = element_text(size=6),
          plot.tag = element_text(size=6)))

Figure S2D

(d10_malaria_volcano <-  lme_res.d10_padj %>% 
   arrange(p.adj, abs(estimate)) %>% 
   ggplot(aes(x=estimate, y=-log10(p.adj), color=FDR)) +
   geom_point(alpha=0.7,size=.5, shape=16) +
   ggrepel::geom_text_repel(data = . %>% filter(FDR ==TRUE, abs(estimate) >1),
                            aes(label = Assay), color="black",
                            force        = 0.5,
                            direction    = "both",
                            segment.size = 0.2,
                            segment.alpha=.1,
                            show.legend = F,
                            size=1.5,
                            max.overlaps = 16,
                            box.padding = unit(0.2, "lines"),
                            point.padding = unit(0.5, "lines"),
                            segment.color = 'grey50'
   ) +
   theme_minimal() +
   geom_vline(xintercept = c(-1, 1), linetype = "dotted", size = .5) +
   geom_hline(yintercept = -log10(0.01), linetype = "dotted", size = .5) + 
   scale_x_continuous(breaks=c(-2.5,-1.0,0.0,1.0,2.5,5.0),limits = c(-2.5,5)) +
   labs(x="Estimated difference (NPX)",
        y="-log10(adj. p-value)",
        subtitle= "D10 after disease vs. convalescence",
        caption=paste0("DAP: ",lme_res.d10_padj %>% filter(FDR==TRUE) %>% nrow(),"\n",
                       "DAP up: ",lme_res.d10_padj %>% filter(FDR==TRUE,estimate>0) %>% nrow(),"\n",
                       "DAP FC>1: ",lme_res.d10_padj %>% filter(FDR==TRUE,estimate>1) %>% nrow(),"\n")) +
   theme(legend.position = "none",
         text = element_text(size=6)) +
   scale_color_manual(values= c(time3_col[[3]],time3_col[[2]])))

Figure S2E

(acute_d10_comp <- dap.res %>% 
   ungroup() %>% 
   arrange(-logFC) %>% 
   mutate(row_id=row_number()) %>% 
   mutate(Assay_orders = factor(as.factor(row_id), levels = row_id, labels = Assay),
          Assay_orders = row_id) %>% 
   left_join(lme_res.d10_padj, by=c("Assay","UniProt"),suffix = c(".acute",".d10")) %>% 
   mutate(d = ifelse(estimate>logFC,T,F),
          d_dbl = abs(logFC-estimate)) %>%
   
   ggplot(aes(x=Assay_orders)) +
   geom_segment(data = . %>% filter(p.adj.d10<=0.01, estimate >1), 
                aes(group=Assay, x = Assay_orders, xend = Assay_orders,yend = logFC, y=estimate, color=d), lwd=0.1) +
   geom_point(aes(y=logFC), size=.05, alpha=1, color=time3_col[[1]]) +
   geom_point(data = . %>% filter(p.adj.d10 <=0.05), aes(y=estimate),color=time3_col[[2]], size=.05,alpha=1) +
   
   ggrepel::geom_text_repel(data = . %>% filter(p.adj.d10<=0.05, estimate >1) %>%
                              filter(d==TRUE) %>% 
                              slice_max(order_by = d_dbl,n=10),
                            aes(label = Assay,y=estimate, color=d), 
                            force        = 0.5,
                            direction    = "both",
                            segment.size = 0.1,
                            min.segment.length = 1,
                            nudge_x = 1,
                            show.legend = F,
                            size=2,
                            max.overlaps = 16,
                            box.padding = unit(0.1, "lines"),
                            point.padding = unit(0.5, "lines"),
                            segment.color = 'black') + 
   scale_color_manual(values=c("FALSE" = "navy","TRUE"="red"), labels=c("lower at D10","higher at D10")) +
   geom_hline(yintercept = 0,linetype=3, color=time3_col[[3]]) +
   scale_x_continuous(expand=c(.1,0),
                      trans = "sqrt") + 
   labs(color = NULL,
        x="Proteins ranked by estimated difference (NPX)\nat acute malaria",
        y="Estimated difference (NPX)") +
   theme_minimal() +
   theme(text = element_text(size=6)) 
)

Supplementary Figure 3

related to main Figure 1

Figure S3A

require(clusterProfiler)

length(unique(data$UniProt)) ## 1463
## [1] 1463
entrez_uniprot_name_mapping <- clusterProfiler::bitr(unique(data.long$UniProt), 
                                                     fromType="UNIPROT",
                                                     toType=c("SYMBOL","ENTREZID"),
                                                     OrgDb="org.Hs.eg.db") %>% 
  dplyr::rename(UniProt = UNIPROT,
                Symbol = SYMBOL,
                Entrez = ENTREZID) 

ranks_entrez <- entrez_uniprot_name_mapping %>% 
  inner_join(dap.res %>% ungroup() %>% filter(p.adj<=0.01), by="UniProt") %>%
  arrange(-logFC) %>%
  dplyr::select(Entrez, logFC) %>% deframe()

### KEGG
## all explore proteins
universe.proteins <- data.long %>% distinct(Assay,UniProt) %>% inner_join(entrez_uniprot_name_mapping,by="UniProt")
## prep enrich input
sig_proteins_df <- entrez_uniprot_name_mapping %>% 
  inner_join(dap.res %>% ungroup(), by="UniProt") %>% filter(p.adj <= 0.01) 

# From significant results, we want to filter on log2fold change
sig_proteins <- sig_proteins_df$logFC
# Name the vector
names(sig_proteins) <- sig_proteins_df$Entrez
# omit NA values
sig_proteins <- na.omit(sig_proteins)
# filter on min log2fold change (log2FoldChange > 1)
sig_proteins <- names(sig_proteins)[abs(sig_proteins) > 1]


cp_KEGG.res <- enrichKEGG(
  sig_proteins,
  organism = "hsa",
  #keyType = "UNIPROT",
  pvalueCutoff = 1,
  pAdjustMethod = "BH",
  universe = universe.proteins$Entrez,
  minGSSize = 10, 
  maxGSSize = 500,
  qvalueCutoff = 1,
  use_internal_data = F
)

#data.frame(cp_KEGG.res)


(cp.kegg.acutefc1 <- data.frame(cp_KEGG.res) %>%
    separate(GeneRatio, into=c("hit","total"),sep="/",remove = F,convert=TRUE) %>% 
    head(10) %>% 
    mutate(ratio = hit/total) %>% 
    
    ggplot(aes(x=fct_reorder(Description, -ratio,.desc = TRUE), y=ratio)) +
    geom_bar(stat = "identity", width = 0.05) +
    geom_point(aes(color=-log10(p.adjust))) +#size = 3) +
    geom_text(aes(label=hit),size=2, nudge_y = .01)+
    scale_y_continuous(expand = c(0.02,0), trans = "pseudo_log") +
    scale_x_discrete(expand = c(-0.01, 1)) +
    theme_minimal() +
    theme(text = element_text(size=6 ),
          axis.text.y = element_text(size = 6),
          axis.ticks.x = element_blank()) +
    coord_flip() +
    guides(size = guide_legend(reverse=TRUE)) +
    labs(title = "KEGG_2021_Human",
         x= NULL,
         y = "ratio [protein/total]",
         size="Protein\noverlapp",
         color=expression("-Log"[10]*"(p.adj)"))
  )

Figure S3B

require(pathview)

sig_proteins_df <- entrez_uniprot_name_mapping %>% 
  inner_join(dap.res %>% ungroup(), by="UniProt") %>% filter(p.adj <= 0.01, abs(logFC)>1) 


logFC <- sig_proteins_df$logFC
names(logFC) <- sig_proteins_df$Entrez
pv.out <- pathview(gene.data = logFC, 
                   pathway.id = "hsa04060", 
                   species = "hsa", 
                   limit = list(gene=5, cpd=1),
)

knitr::include_graphics("hsa04060.pathview.png")
KEGG

KEGG

Figure 2

Potential sources and functionalities of plasma proteins during acute malaria

Figure 2A

secretome_location_dap <- dap.res %>% 
  dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>% 
  inner_join(hpa_24.0, by=c("Assay"="gene","UniProt"="uniprot")) %>% 
  mutate(secretome_location_tissue_spec = case_when(secretome_location=="Not secreted"~ paste0(secretome_location," - ",rna_tissue_specificity),
                                                   .default = secretome_location)) %>% 
  group_by(secretome_location_tissue_spec) %>% 
  count(sort = TRUE) 

## change order
secretome_location_dap.order <- secretome_location_dap %>% pull(secretome_location_tissue_spec)
secretome_location_dap.order <- c("Secreted to blood","Intracellular and membrane","Secreted in other tissues","Secreted to extracellular matrix",
                                  "Secreted to digestive system", "Secreted in brain", "Secreted - unknown location", "Secreted in female reproductive system",
                                  "Secreted in male reproductive system",
                                  "Not secreted - Tissue enriched", "Not secreted - Tissue enhanced","Not secreted - Group enriched", "Not secreted - Low tissue specificity")

## plot everything
(hpa.protein.origin.overview <- secretome_location_dap %>% 
    ungroup() %>% 
    mutate(secretome_location_tissue_spec = factor(as.factor(secretome_location_tissue_spec), levels=rev(secretome_location_dap.order))) %>% 
    ggplot(aes(x=secretome_location_tissue_spec,y=n,fill=secretome_location_tissue_spec)) +
    geom_col(width = 0.5) +
    geom_text(aes(label=n),size=2, nudge_y = -.2) +
    coord_flip() +
    scale_y_continuous(trans="pseudo_log",name = NULL, sec.axis = sec_axis(~.,labels = NULL,breaks = NULL, name = "Number of DAPs"),
                       #expand=c(0,.15)
                       expand=c(0,0)

                       ) +
    theme_bw() +
    theme(axis.text.y = element_text(size = 6),
          axis.text.x = element_text(size = 6),
          legend.text=element_text(size=6),
          legend.title=element_text(size=6),
          plot.title = element_text(size=6))+
    scale_fill_manual(values=secretome_location_tissue_spec_cols,
                      limits = secretome_location_dap.order) +
    labs(fill="Protein\norigin\nby HPA",
         x=NULL))

temp.df <- dap.res %>% 
  dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>% 
  inner_join(hpa_24.0, by=c("Assay"="gene","UniProt"="uniprot")) %>% 
  mutate(secretome_location_tissue_spec = case_when(secretome_location=="Not secreted"~ paste0(secretome_location," - ",rna_tissue_specificity),
                                                   .default = secretome_location))

Figure 2B

df1 <- temp.df %>% 
  transmute(Assay, logFC, p.adj, direction,secretome_location_tissue_spec, secretome_function) 

df2 <- df1 %>% 
  group_by(secretome_location_tissue_spec) %>% 
  summarise(atlas_name_count = n()) %>% 
  left_join(
    df1 %>% 
      group_by(secretome_location_tissue_spec, secretome_function, direction) %>% 
      summarise(function_name_count = n()),
    by="secretome_location_tissue_spec") %>% 
  left_join(
    df1 %>% group_by(secretome_location_tissue_spec, secretome_function, direction) %>% 
      summarise(median_logFC = median(logFC)),
    by=c("secretome_location_tissue_spec", "secretome_function","direction"))

(hpa.function.bubbleplot <- df2 %>% 
    filter(!secretome_location_tissue_spec %in% c("NULL", "NA","no mapping"),
           !secretome_function %in% c("NULL")) %>% 
    mutate(secretome_function = case_when(is.na(secretome_function) ~ "No secretome function",
                                          .default = secretome_function)) %>% 
    mutate(secretome_location_tissue_spec = factor(as.factor(secretome_location_tissue_spec),
                                                  levels=rev(secretome_location_dap.order))) %>% 
    ggplot(aes(x=median_logFC,
               y= fct_reorder2(secretome_function, 
                               atlas_name_count,
                               function_name_count,.desc = F))) +
    geom_point(aes(size=function_name_count, color=secretome_location_tissue_spec), show.legend = T) +
    geom_vline(xintercept = 0,linetype=1) +
    geom_text(aes(label = function_name_count),
              size=2, color="grey20",show.legend = F, parse = F) +
    labs(x="median estimated difference (NPX)",
         y=NULL,
         title = "Number DAPs per HPA function",
         size="Number of proteins",
         caption="Size: number of proteins",
         color = "HPA source") +
    scale_color_manual(values=secretome_location_tissue_spec_cols, limits = secretome_location_dap.order) +
    scale_x_continuous(trans = "pseudo_log") +
    scale_y_discrete(expand = c(0,1))+
    guides(size = "none") +
    theme_minimal() +
    scale_size(range=c(3,6)) +
    theme(text = element_text(size=6))
)

Figure 2C

(acute_malaria_hpa_source <- temp.df %>% 
    right_join(top25 %>% transmute(Assay,logFC)) %>% 
    
    ggplot(aes(x=fct_reorder(Assay,logFC), y=logFC, color=secretome_location_tissue_spec)) +
    geom_point(show.legend = TRUE,size=1) +
    geom_col(width = .05,show.legend = F) +
    scale_y_continuous(sec.axis = sec_axis(~.,labels = NULL,breaks = NULL, name = "Top25 DAP")) +
    coord_flip() +
    theme_minimal() +
    theme(plot.title.position = "plot",
          axis.text.y = element_text(size = 4),
          axis.text.x = element_text(size = 6),
          axis.title.x = element_text(size = 6),
          panel.grid.major = element_blank()) +
    labs(color="HPA source",
         x="",
         y="Estimated difference (NPX)",
         title = "Protein source according to Human Protein Atlas") +
    scale_color_manual(values=secretome_location_tissue_spec_cols,
                       limits=secretome_location_dap.order))

Supplementary Figure 4

related to main Figure 2

Figure S4A

malaria.daps.hpa23 <- dap.res %>% 
  arrange(desc(abs(logFC)),desc(p.adj)) %>% 
  filter(p.adj<=0.01) %>% 
  arrange(-logFC) %>% 
  left_join(hpa_24.0,by=c("UniProt" = "uniprot")) %>% 
  ungroup()

## abundant proteins in acute malaria plasma, not immune cell specific nor predicted to be secreted
## => tissue leakage??
malaria.tissue.leakage <- malaria.daps.hpa23 %>% 
  filter(is.na(rna_blood_cell_specificity) | 
           rna_blood_cell_specificity=="Not detected in immune cells", 
         rna_tissue_specificity %in% c("Tissue enriched"),#,"Group enriched","Tissue enhanced"),
         secretome_location =="Not secreted",
         logFC >0)#.5)

secretome.location.order <- c("Secreted to blood","Intracellular and membrane","Secreted in other tissues","Secreted to extracellular matrix",
                                  "Secreted to digestive system", "Secreted in brain", "Secreted - unknown location", "Secreted in female reproductive system",
                                  "Secreted in male reproductive system","Not secreted")
secretome.fun.count <- malaria.daps.hpa23 %>% group_by(secretome_function) %>% count() %>% arrange(-n) %>% pull(secretome_function)

df <- malaria.daps.hpa23 %>% 
  filter(logFC>=0) %>% 
  transmute(Assay,
            direction,
            secretome_location = factor(secretome_location, levels= secretome.location.order),
            secretome_function = factor(secretome_function, levels = secretome.fun.count),
            rna_blood_cell_specificity,
            rna_tissue_specificity = factor(rna_tissue_specificity, levels = c("Tissue enriched",
                                                                               "Group enriched",
                                                                               "Tissue enhanced",
                                                                               "Low tissue specificity",
                                                                               "Not detected")),
            tissue_enriched = factor(case_when(rna_blood_cell_specificity=="Not detected in immune cells" & rna_tissue_specificity == "Tissue enriched" & secretome_location =="Not secreted" & direction == "up" ~"1",
                                               .default = "0"), 
                                     levels=c("1","0"), 
                                     labels=c("1"="Tissue specific and not secreted",
                                              "0"="Less tissue specific")
            ))
(dap.origin.w.tl <- df %>%
    ggplot(aes(axis1 = secretome_location,
               axis2 = secretome_function,
               axis3 = rna_tissue_specificity,
               axis4 = tissue_enriched
    )) +
    geom_alluvium(aes(fill = secretome_location),width = 1/12,geom = "flow", lode.guidance = "forward",) +
    geom_stratum(aes(fill=secretome_location),width = 1/12) +
    ggfittext::geom_fit_text(stat = "stratum", aes(label = after_stat(stratum)),min.size = 1, show.legend = F) +
    scale_x_discrete(limits = c("Secretome\nlocation","Secretome\nfunction", "Tissue specificity\n(based on gene expression)","Tissue specificity\n(overall)"), expand = c(.2, .05)) +
    theme_bw() +
    scale_fill_manual(values= c(secretome_location_cols,"NA"="red","SPEC"="white")) +
    labs(title = "Abundant proteins in blood during acute malaria",
         y= "Number of proteins") +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          axis.ticks.x = element_blank(),
          panel.background = element_rect(colour = "black", size=0.5, fill=NA),
          panel.border = element_rect(size = 0.2, colour = "grey"),
          legend.position = "none"))

Figure S4B

(alluvial_proteinorigin <- df %>%
   ggplot(aes(axis1 = secretome_location,
              axis3 = rna_tissue_specificity,
              axis4 = tissue_enriched
   )) +
   geom_alluvium(aes(fill = tissue_enriched),width = 1/12,geom = "flow", lode.guidance = "forward",) +
   geom_stratum(aes(fill=secretome_location),width = 1/12) +
   ggfittext::geom_fit_text(stat = "stratum", aes(label = after_stat(stratum)),min.size = 1, show.legend = F) +
   
   scale_x_discrete(limits = c("Secretome\nlocation",#"Secretome\nfunction", 
                               "Tissue specificity\n(based on gene expression)","Tissue specificity\n(overall)"), expand = c(.2, .05)) +
   theme_bw() +
   scale_fill_manual(values= c("Tissue specific and not secreted"="red","Less tissue specific"="grey90")) +
   labs(title = "Potential tissue leakage proteins in blood during acute malaria",
        y= "Number of proteins") +
   theme(panel.grid.major = element_blank(),
         panel.grid.minor = element_blank(),
         axis.ticks.x = element_blank(),
         panel.background = element_rect(colour = "black", size=0.5, fill=NA),
         panel.border = element_rect(size = 0.2, colour = "grey"),
         legend.position = "none"))

malaria.tissue.leakage <- df %>% filter(tissue_enriched=="Tissue specific and not secreted") %>% pull(Assay)

Figure S4C

### tissue expression¨
mat <- hpa.tissue %>% 
  filter(gene_name %in% c(malaria.tissue.leakage)) %>% 
  pivot_wider(names_from = tissue, values_from = n_tpm, values_fn = median) %>% 
  dplyr::select(-gene) %>% 
  column_to_rownames("gene_name")

mat1 <- mat %>% 
  t() %>% 
  scale() %>% 
  scales::rescale(to=c(0,1)) %>% 
  t() 

(hm.tissue.leakage <- mat1 %>% 
    t() %>% 
    Heatmap(row_names_gp = gpar(fontsize=6),
            column_names_gp =  gpar(fontsize=4),
            cluster_rows = T,
            cluster_columns = T,
            name="scaled\nnTPM",
            column_title = "High abundant plasma proteins\n 'Tissue specific and not secreted'",
            column_title_gp = gpar(fontsize=6),
            col = circlize::colorRamp2(c(min(mat1),max(mat1)), c("white","red")),
            column_dend_height = unit(5,"mm"),
            row_dend_width = unit(5,"mm"),
            heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                        title_gp = gpar(fontsize = 6),
                                        legend_height = unit(20, "mm")))
)

Figure S4D

(tissue.leakage.violine <- data.long %>% 
   inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),
              by="sample_id") %>% 
   dplyr::filter(Assay %in% c(malaria.tissue.leakage),#"DEFA1","DEFA1B"),
                 Time!="D10") %>% 
   mutate(Assay = factor(Assay, levels = c(malaria.tissue.leakage))) %>% #,"DEFA1","DEFA1B"))) %>% 
    ggplot(aes(x=Time, y=NPX, color=Time,fill=Time)) + 
    geom_line(aes(group=study_id), color="grey",alpha=.6,size=.2)+
    geom_violin(trim = F,alpha=.2,lwd=.25) +
    geom_boxplot(alpha=1,width=0.25,color="black",outlier.size = 0.5, fatten = 1,lwd=.25,show.legend = F) +
    facet_wrap(~Assay,ncol = 9,scales = "free_y") +
    theme_minimal() +
    labs(x="") +
    theme(axis.text.x = element_blank(),# element_text(size=6),
          legend.position = "bottom") +
    scale_color_manual(values=time3_col) +
    scale_fill_manual(values=time3_col))

Revision extra

df <-  data.long %>% 
   inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),
              by="sample_id") %>% 
  filter(Assay%in% c("AGXT","HAO1"),
         Time=="Acute") %>% 
  left_join(
    clinchem_study_pats_acute.wide %>% transmute(study_id, p_asat, p_alat)
  ) %>% 
  pivot_longer(names_to = "clinchem", values_to = "clinchem_val",cols = p_asat:p_alat)

#cor.test.res <- tidy(cor.test(df$`CD19+ CD20+BAFF-R`,df$TNFSF13B,method = "spearman"))
df %>% 
  transmute(sample_id, Assay,NPX,clinchem,clinchem_val) %>% 
  pivot_wider(names_from = Assay, values_from = NPX) %>%
  pivot_wider(names_from = clinchem, values_from = clinchem_val) %>% 
  column_to_rownames("sample_id") %>% 
  correlation() %>% 
  tibble() %>% 
  filter(Parameter1!=Parameter2,
         Parameter2!="HAO1")
## # A tibble: 5 × 11
##   Parameter1 Parameter2     r    CI CI_low CI_high     t df_error       p Method
##   <chr>      <chr>      <dbl> <dbl>  <dbl>   <dbl> <dbl>    <int>   <dbl> <chr> 
## 1 AGXT       p_asat     0.569  0.95 0.233    0.784  3.39       24 0.00962 Pears…
## 2 AGXT       p_alat     0.410  0.95 0.0994   0.648  2.66       35 0.0273  Pears…
## 3 HAO1       p_asat     0.396  0.95 0.0101   0.679  2.11       24 0.0453  Pears…
## 4 HAO1       p_alat     0.423  0.95 0.115    0.657  2.76       35 0.0273  Pears…
## 5 p_asat     p_alat     0.660  0.95 0.366    0.834  4.30       24 0.00123 Pears…
## # ℹ 1 more variable: n_Obs <int>
df %>% 
  ggplot(aes(x=NPX,y=clinchem_val)) +
  #geom_point(shape=16, size=.5) +
  geom_point() +
  geom_smooth(method="lm") +
  facet_grid(Assay~clinchem)

  #scale_color_manual(values=endemic2_col)+
  #annotate("text",
  #         x=2,
  #         y=7500,
  #         size=1.5,
  #         label=paste("\nrho: ",round(cor.test.res$estimate,2),
  #                     "\np-value:",scales::scientific_format()(cor.test.res$p.value))) +
  #labs(x="TNFSF13B [NPX]\nat Acute",
   #    y="CD19+ CD20+BAFF-R [MFI]\nat Acute",
    #   color=NULL))

library(see)
df %>% 
  transmute(sample_id, Assay,NPX,clinchem,clinchem_val) %>% 
  pivot_wider(names_from = Assay, values_from = NPX) %>%
  pivot_wider(names_from = clinchem, values_from = clinchem_val) %>% 
  column_to_rownames("sample_id") %>% 
  correlation() %>% 
  summary() %>% 
  plot() +

  theme(text = element_text(size=12))

Supplementary Figure 5

related to main Figure 2 ### Figure S5A-D

i="Secreted to blood"
acute_malaria_hpa_function_facet.list <- list()
for(i in c("Secreted to blood","Intracellular and membrane","Secreted in other tissues","Secreted to extracellular matrix","Secreted to digestive system","Secreted in brain","Secreted - unknown location")){
  
  (acute_malaria_hpa_function_facet.list[[i]] <- 
     dap.res %>% 
     dplyr::filter(FDR==TRUE,
                   abs(logFC)>0) %>%
     inner_join(hpa_24.0,by=c("Assay"="gene")) %>% 
     dplyr::filter(secretome_location == i, 
                   !secretome_function %in% c(NA,"NULL","Not secreted")
     ) %>% 
       ungroup() %>% 
       mutate(secretome_function = factor(secretome_function))%>% 
       ggplot(aes(x = fct_reorder2(Assay, secretome_function, -logFC),
                  y=logFC, color = secretome_location)) +
       geom_point(size=1, show.legend = F) + 
       geom_errorbar(aes(ymin= logFC - 1.96*SE,# 1.96*SE =conf.low
                         ymax=logFC + 1.96*SE,#conf.high,
                         color=secretome_location),
                     size=.25,    
                     width=.2,
                     position=position_dodge(.9),
                     alpha=.5) +
       geom_hline(yintercept = 0, linetype=2, alpha=.4) + 
       scale_color_manual(values = secretome_location_cols) +
       coord_flip() +
       theme_minimal() +
       facet_grid(cols = vars(secretome_location), 
                  rows = vars(secretome_function), scales = "free", space = "free_y",drop = F) +
       theme(strip.text.y = element_text(angle = 0,size=3.5),
             strip.placement = "inside",
             axis.text = element_text(size = 3),
             axis.title = element_text(size=5),
             legend.title = element_text(size=5),
             legend.text = element_text(size=5),
             plot.caption = element_text(size=5),
             panel.grid.major.y = element_blank(),
             panel.grid.minor.y = element_blank(),
             panel.grid.major.x = element_line(linewidth = .5),
             panel.grid.minor.x = element_line(linewidth = .5),
             plot.title.position = "plot",
             legend.position = "none") +
       labs(x="",
            y="Estimated difference (NPX) with 95% CI") +
       expand_limits(y = c(-1,1))
  )
}

delta NPX

  • needed for heatmap annotation and later on clustering
df_4_fc <- data.wide %>% 
  inner_join(sampleTable_simple %>% dplyr::select(DAid,study_id, sample_id, Time),by="sample_id") %>% 
  dplyr::filter(Time!="D10") %>% 
  dplyr::select(DAid,study_id, sample_id, Time, everything()) %>% 
  pivot_longer(cols = 5:ncol(.), names_to = "Assay", values_to = "NPX") %>% 
  dplyr::select(-DAid,-sample_id) %>% 
  pivot_wider(values_from = "NPX", names_from = "Time")


M12_median_M12 <- df_4_fc %>% 
  group_by(Assay) %>% 
  summarise(m12_median = median(M12,na.rm = TRUE)) 

fc_over_median_M12 <- df_4_fc %>% 
  inner_join(M12_median_M12, by="Assay") %>% 
  group_by(Assay) %>% 
  mutate(log2FC_medianM12 = Acute-m12_median) %>% 
  dplyr::select(-M12) %>% 
  na.omit() %>% 
  dplyr::rename(dNPX = log2FC_medianM12) 

#fc_over_median_M12 %>% saveRDS("../data/data_clean/20230426_Explore1536_fc_over_median_m12_tidy_long.rds")
fc_over_median_M12 %>% head()
## # A tibble: 6 × 5
## # Groups:   Assay [6]
##   study_id Assay   Acute m12_median   dNPX
##   <chr>    <chr>   <dbl>      <dbl>  <dbl>
## 1 2011PT01 NPPB    1.48      0.0487  1.43 
## 2 2011PT01 HNRNPK -0.193     0.658  -0.851
## 3 2011PT01 CEBPB   0.702     0.140   0.562
## 4 2011PT01 CRHR1  -0.829     0.0427 -0.872
## 5 2011PT01 TSLP    0.952     0.154   0.798
## 6 2011PT01 MFAP3   0.871     0.0906  0.781

Figure 3

Single-cell transcriptomics of PBMCs during acute malaria

df <- data.wide %>% 
  inner_join(sampleTable_simple %>% 
               transmute(sample_id),
             by="sample_id") %>% 
  column_to_rownames("sample_id")

## PC calculation
pcaRes <- stats::prcomp(df,center = TRUE, scale. = TRUE)
varExp <- round(pcaRes$sdev^2 / sum(pcaRes$sdev^2) * 100)
pcaDF <- data.frame(PC1 = pcaRes$x[, 1],
                    PC2 = pcaRes$x[, 2]) %>% 
  rownames_to_column("sample_id") 

## Prep for plotting
data4plot <- pcaDF %>% 
  dplyr::inner_join(sampleTable_simple, by="sample_id") %>% 
  mutate(rhapsody_lib = ifelse(study_id == "2013004","Library 1",
                               ifelse(study_id == "2013007","Library 2",
                                      ifelse(study_id == "2013008","Library 3",
                                             ifelse(study_id == "2018002","Library 4",NA)))))


(plot.pca.rhapsody <- data4plot %>% 
    ggplot(mapping = aes(x = PC1, y = PC2, color = Time,fill=NULL, label = NULL)) +
    geom_point(alpha = 0.9, size = 1) +
    ggrepel::geom_text_repel(data= . %>% filter(study_id %in% rhapsody_study_ids), 
                             aes(x=PC1,y=PC2, label=rhapsody_lib),color="grey10",
                             direction = "both",box.padding = 1, max.overlaps = Inf,
                             size=3, alpha=.9,show.legend = F) +
    geom_point(data= . %>% filter(study_id %in% rhapsody_study_ids),
               aes(color=Time),
               size=0.5, alpha=.8) +
    guides(colour = guide_legend(override.aes = list(size=1,alpha=1)))+
    ggplot2::scale_color_manual(values= time3_col) +
    labs(x = paste0("PC1 (",  varExp[1], " %)"),
         y = paste0("PC2 (",  varExp[2], " %)"),
         shape="Rhapsody library") +
    theme_minimal()  +
    theme(legend.title = element_text(size = 6), 
          legend.text = element_text(size = 6))) 

load seurat object & set colors

library(Seurat)
#pbmc <- readRDS("../../MalariaTraveller_AbSeq/data/SeuratObjects/2021-12-17AbSeq_Cell_Calling_qc_cca_wnn_clustering_annotated.rds")
#pbmc <- readRDS("../data/data/rhapsody/2021-12-17AbSeq_Cell_Calling_qc_cca_wnn_clustering_annotated.rds")
pbmc <- readRDS("../data/data/rhapsody/MalariaTraveler_RhapsodyAbSeq_Cell_Calling_qc_cca_wnn_clustering_annotated.rds")

pbmc$Group_rev <- factor(as.factor(pbmc$Group), levels = c("primary", "previously"))

#- RNA Normalization
pbmc <- NormalizeData(object = pbmc, assay = 'RNA', normalization.method = 'LogNormalize', scale.factor = 10000)

#- Ab Normalization
pbmc <- NormalizeData(object = pbmc, assay = 'ADT', normalization.method = 'CLR') #margin   If performing CLR normalization, normalize across features (1) or cells (2)

## list of proteins/mrna targets covered
ab.markers <- rownames(pbmc@assays$ADT)
rna.markers <- rownames(pbmc@assays$RNA)

##change group color
ENDEMIC_colors <- setNames(c("#F1A340","#998EC3"), c("previously_exposed","primary_infected"))
#previously_exposed   primary_infected 
#         "#F1A340"          "#998EC3" 
ENDEMIC_colors <- setNames(brewer.pal(3,"PuOr")[c(1,3)], c("previously_exposed","primary_infected"))
names(ENDEMIC_colors) <- c("previously","primary")
TIME_colors <- setNames(brewer.pal(6,"PiYG"), c("Acute","D10","M1","M3","M6","Y1"))

scaled_01_col <- circlize::colorRamp2(c(0,1), c("white","red"))

L1_colors <- length(unique(pbmc@meta.data$CellType_L1))
L1_colors <- c("#68a748",
               "#8761cc",
               "#ae953e",
               "#688bcc",
               "#cc693d",
               "#4aac8d",
               "#c361aa",
               "#ca5369")
names(L1_colors) <- unique(pbmc@meta.data$CellType_L1)


Idents(pbmc) <- "CellType_L2"

L2_colors <- length(unique(pbmc@meta.data$CellType_L2))
L2_colors <- c("mDC"="#79658C",
               "pDC" = "#AEA14E",
               
               "CD14 monocytes"= "#D1EAB7",
               "CD16 monocytes"="#DB7D47",
               
               "Vd2+ gdT"="#796CD7",
               "Vd2- gdT" =  "#66AC55",
               
               "NK CD56dim CD16+" = "#EBB69E", 
               "NK CD56dim" =  "#CEE486",
               "NK CD56bright"=  "#E0DADB",
               "NK prolif." ="#B5E7DF",
               
               "B naive" = "#889AE5",
               "B memory" = "#66ED58",
               "Plasma cells" = "#893CEA",
               
               "CD4 naive"= "#E15081",
               "CD4 Treg CD80+"= "#579189",
               "CD4 Treg CD80-"=  "#66DEE2",
               "CD4 Tfh"= "#D64EDB",
               "CD4 effect. activated" = "#D38D96",
               "CD4 effect. memory" = "#EDD591",
               "CD4 trans. memory" =  "#DAB8E3",
               "CD4 central memory"  = "#6FE8BE",
               
               "CD8 naive"= "#CAEB48",
               "CD8 trans. memory"= "#85EB8F",
               "CD8 Tfh"="#E6D253",
               "NKT"="#7BBCDF",
               "CD8 effect. memory"  =  "#A7AE90", 
               "undefined"= "#D984D1")

names(L2_colors) <- unique(pbmc@meta.data$CellType_L2)

Figure 3A, C

arr <- list(x = -13, y = -13, x_len = 5, y_len = 5)

umap_axis <- annotate("segment", linewidth=0.1,
                      x = arr$x, xend = arr$x + c(arr$x_len, 0), 
                      y = arr$y, yend = arr$y + c(0, arr$y_len), 
                      arrow = arrow(type = "closed", length = unit(3, 'pt')))
umap_axis_xlab <- annotate("text", x = arr$x+2.5, y = arr$x-1, label = "wnnUMAP 1",size=1) 
umap_axis_ylab <- annotate("text", y = arr$y+2.5, x = arr$y-1, label = "wnnUMAP 2",size=1,angle=90)


rhapsody_umap_coords <- data.table::data.table(pbmc@meta.data, Embeddings(object = pbmc, reduction = 'wnn.umap')) %>% rownames_to_column("CellID") 

lable_df <- rhapsody_umap_coords %>%
  dplyr::group_by(CellType_L1) %>%
  dplyr::select(CellType_L1, contains("UMAP")) %>%
  summarise_all(mean)

(rhapsody_umap_ggplot_l1 <- rhapsody_umap_coords %>% 
    ggplot(aes(x = wnnUMAP_1, y = wnnUMAP_2)) + 
    geom_point(aes(color = as.character(CellType_L1)), size = 0.1, alpha=.5, show.legend = F,shape = 16) +
    ggrepel::geom_text_repel(data=lable_df,aes(x=wnnUMAP_1,y=wnnUMAP_2, label=CellType_L1),size=1.5) +
        coord_fixed()+
    scale_color_manual(values=L1_colors) +
    theme_void() +
                umap_axis +
                umap_axis_xlab +
                umap_axis_ylab)

lable_df <- rhapsody_umap_coords %>%
  dplyr::group_by(CellType_L2) %>%
  dplyr::select(CellType_L2, contains("UMAP")) %>%
  summarise_all(mean)

(rhapsody_umap_ggplot_l2 <- rhapsody_umap_coords %>% 
    ggplot(aes(x = wnnUMAP_1, y = wnnUMAP_2)) + 
    geom_point(aes(color = as.character(CellType_L2)), size = 0.1, alpha=.5, show.legend = F, shape = 16) + 
    ggrepel::geom_text_repel(data=lable_df,aes(x=wnnUMAP_1,y=wnnUMAP_2, label=CellType_L2),size=1.5) +
    labs(x = 'wnnUMAP 1', y = 'wnnUMAP 2', color=NULL)  + 
    coord_fixed()+
    scale_color_manual(values=L2_colors) +
    theme_void() +
                umap_axis +
                umap_axis_xlab +
                umap_axis_ylab)

Figure 3B

require(scales)
(per_sample_perc_l1 <- tibble(pbmc@meta.data) %>% 
    mutate(orig.ident = paste0("Patient"," 0",Library)) %>% 
    group_by(Time,orig.ident) %>% 
    count(CellType_L1) %>% 
    # Stacked + percent
    ggplot(aes(fill = CellType_L1, y=n, x=orig.ident)) + 
    geom_bar(position="fill", stat="identity",width = 0.9) +
    scale_fill_manual(values = L1_colors) +
    facet_grid(~Time,scales = "free_x") +
    scale_y_continuous(labels = scales::percent,expand = c(0,0)) + 
    labs(x = "",
         y = "Frequency",
         fill="") +
    theme_minimal(base_size = 6) +
    #theme_cowplot() +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
          panel.grid.major = element_blank()))

Figure 3D

pbmc_acute <- subset(pbmc, subset=Time=="Acute")

#- RNA Normalization
pbmc_acute <- NormalizeData(object = pbmc_acute, assay = 'RNA', normalization.method = 'LogNormalize', scale.factor = 10000) %>% ScaleData()

#- Ab Normalization
pbmc_acute <- NormalizeData(object = pbmc_acute, assay = 'ADT', normalization.method = 'CLR') #margin   If performing CLR normalization, normalize across features (1) or cells (2)
## Pseudobulk (Celltype)

#https://github.com/satijalab/seurat/discussions/4210
## AverageExpression
Idents(pbmc_acute) <- "CellType_L2"

## calculation of pseudobulk, for each identity based on count data
pbmc_acute.avg.wide <- log1p(Seurat::AverageExpression(pbmc_acute, group.by = "CellType_L2", slot = "counts", verbose = FALSE)$RNA) %>% 
  data.frame() %>% 
  rownames_to_column("gene") 

colnames(pbmc_acute.avg.wide) <- c("gene",colnames(Seurat::AverageExpression(pbmc_acute, group.by = "CellType_L2", slot = "counts", verbose = FALSE)$RNA))

pbmc_acute.avg.long <- pbmc_acute.avg.wide %>% pivot_longer(names_to = "celltype", values_to = "avgExp",cols = -gene)

Mapping (gene - protein)

## mapping 
full_mapping <- mapping_uniprot_ensembl %>% left_join(hpa_24.0, by=c("Ensembl"="ensembl"))

wilcoxUp <- dap.res %>% filter(FDR==TRUE,logFC>1) %>% pull(UniProt)

gene.selection <- full_mapping %>% 
  filter(UniProt %in% wilcoxUp) %>% 
  filter(Symbol %in% rna.markers) %>% distinct(Assay) %>% pull(Assay)

Figure 3D

Heatmap genes expression

rhapsody.gene.match <- full_mapping %>% 
  filter(UniProt %in% wilcoxUp) %>% 
  filter(Symbol %in% unique(pbmc_acute.avg.wide$gene))

## make matrix for heatmap
mat_pbmc_acute <- pbmc_acute.avg.wide %>% 
  filter(gene %in% rhapsody.gene.match$Symbol) %>% 
  column_to_rownames("gene") %>% 
  as.matrix() 

## make row(gene/protein) annotation df
rowAnno.df <- data.frame(Assay = rownames(mat_pbmc_acute)) %>% 
  left_join(dap.res,by=c("Assay")) %>% 
  #left_join(hpa_24.0,by=c("Assay"="gene")) %>% 
    left_join(hpa_24.0,by=c("UniProt"="uniprot")) %>% 

  mutate(secretome_function = ifelse(is.na(secretome_function),"No annotated function", secretome_function))
  

col.anno.df <- data.frame(colnames = colnames(mat_pbmc_acute)) %>% 
  transmute(colnames,
            colanno = case_when(grepl("DC",colnames) ~ "DC",
                                grepl("monocytes",colnames) ~ "Monocytes",
                                grepl("CD4",colnames) ~ "CD4+ T",
                                grepl("CD8",colnames) ~ "CD8+ T",
                                grepl("B|Plasma",colnames) ~ "B",
                                grepl("NK",colnames) ~ "NK",
                                grepl("gdT",colnames) ~ "gdT",
                                .default = "undefined"),
            colanno = factor(colanno, levels= c("DC","Monocytes","NK","gdT","B","CD4+ T","CD8+ T","undefined")))


right.anno <- HeatmapAnnotation(df = col.anno.df %>% column_to_rownames("colnames"), 
                                which = "row",
                                col = list(colanno = L1_colors),
                                # name = "SNF cluster",
                                show_annotation_name = F,
                                show_legend = F,
                                annotation_name_gp = gpar(fontsize=6),
                                annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                               title_gp = gpar(fontsize = 6),
                                                               direction = "horizontal",
                                                               legend_height = unit(.1, "cm"),
                                                               grid_width = unit(.2, "cm")),
                                simple_anno_size = unit(1, "mm"))

top.anno <-  HeatmapAnnotation(df = rowAnno.df %>% transmute(Assay, secretome_location) %>% column_to_rownames("Assay"),
                               which = "column",
                               show_legend = c(TRUE), 
                               show_annotation_name = F, 
                               annotation_name_gp = gpar(fontsize = 6),
                               annotation_legend_param = list(title = "HPA\nclassification",
                                                              title_gp = gpar(fontsize = 6), 
                                                              labels_gp = gpar(fontsize = 6),
                                                              legend_height = unit(3, "mm"), 
                                                              grid_width = unit(3, "mm")),
                               col = list(secretome_location = c(secretome_location_cols)),
                               simple_anno_size = unit(3, "mm"),
                               
                               na_col = "grey90")

## getting foldchange (dNPX over median convalescence) 
m <- fc_over_median_M12 %>%
  filter(Assay %in% rowAnno.df$Assay) %>% 
  pivot_wider(names_from = Assay, values_from = dNPX,id_cols = study_id) %>% 
  column_to_rownames("study_id") %>% 
  as.matrix() %>% t()

m <- m[rownames(mat_pbmc_acute),]


bottom.anno <- HeatmapAnnotation("Plasma protein\ndNPX" = anno_boxplot(t(m),
                                                                       height = unit(1.5, "cm"),width = unit(1.5,"cm"),
                                                                       box_width = 0.8,
                                                                       axis_param = list(side = "right",
                                                                                         labels_rot = 45,
                                                                                         gp=gpar(fontsize = 5)),
                                                                       gp = gpar(fill="#C51B7D"),
                                                                       outline = FALSE),
                                 annotation_name_rot = 0,
                                 annotation_name_gp = gpar(fontsize = 5),
                                 annotation_name_side = "right",
                                 simple_anno_size = unit(3, "mm"),
                                 which = "column")



(pbmc_l2_acute_hm.wide <- mat_pbmc_acute[rownames(m),] %>% 
    t() %>% 
    ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% 
    as.matrix() %>% 
    ComplexHeatmap::Heatmap(
      name="average\ngene\nexpression",
      col = scaled_01_col,
      
      top_annotation = top.anno,
      bottom_annotation = bottom.anno,
      right_annotation =  right.anno,
      column_dend_height = unit(2, "mm"),
      cluster_rows = F,
      row_dend_reorder = TRUE,
      show_row_names = TRUE,
      column_split = rowAnno.df$secretome_function,
      column_dend_reorder = F,
      row_title_side = "right",
      row_title_gp = gpar(fontsize = 6),
      cluster_columns = T,
      row_split = col.anno.df$colanno,
      row_title = NULL,
      
      column_title_gp = gpar(fontsize=4),
      column_title_rot = 45,
      row_title_rot = 0,
      row_names_gp = gpar(fontsize = 4),
      #row_dend_width = unit(2, "mm"), 
      row_dend_side = "left",
      cluster_row_slices = T,
      column_names_gp = gpar(fontsize = 4), 
      column_names_rot = 90,
      heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                  title_gp = gpar(fontsize = 6),
                                  grid_width = unit(3, "mm")),
    ) 
  )

Figure 3E

CellPhoneDB

#cpdb.protein_input <- read_delim("../data/cellphoneDB/v4.1.0_protein_input.csv")
#cpdb.interaction_input <- read_delim("../data/cellphoneDB/v4.1.0_interaction_input.csv")

cpdb.protein_input <- read_delim("../data/cellphoneDB/v5_protein_input.csv",)
cpdb.interaction_input <- read_delim("../data/cellphoneDB/v5_interaction_input.csv")

kegg.ccr <- read_excel("../data/KEGG_CytokineCytokineReceptorInteraction_malariaspec.xlsx") %>% mutate(Source = "KEGG")
rna.markers.uniprot <- data.frame(gene = rna.markers) %>% 
  left_join(hpa_24.0 %>% transmute(gene, uniprot)) %>% na.omit()
ligand.q <- dap.res %>% filter(p.adj <=0.01, logFC > .1) %>% 
  left_join(cpdb.protein_input,
            by=c("UniProt"="uniprot")) %>% 
  pull(UniProt)

length(ligand.q)
## [1] 491
nw <- cpdb.interaction_input %>% 
  filter(partner_a %in% ligand.q,
         directionality == "Ligand-Receptor") %>% 
  mutate(protein_name_b_strip = gsub("_HUMAN","",protein_name_b),
         protein_name_a = gsub("_HUMAN","",protein_name_a)) %>% 
  mutate(protein_name_b_complex = case_when(is.na(protein_name_b) ~ str_remove(interactors,paste0(protein_name_a,"-")),
                                    .default = protein_name_b)) %>%
   separate_longer_delim(protein_name_b_complex, delim = "+") %>% 
   left_join(hpa_24.0 %>% transmute(protein_name_b_complex = gene,
                                      uniprot_b_complex = uniprot), by=c("protein_name_b_complex")) %>% 
  mutate(protein_name_b = case_when(is.na(protein_name_b) ~ protein_name_b_complex,
                                        .default = protein_name_b),
         partner_b_new = case_when(is.na(uniprot_b_complex) ~ partner_b,
                                   .default = uniprot_b_complex)) %>% 
  transmute(partner_a, partner_b, partner_b_new) %>% 
  filter(partner_b_new %in% rna.markers.uniprot$uniprot) %>% 
  mutate(uniprot_a = partner_a,
         uniprot_b = partner_b_new)
measured.in.plasma <- dap.res %>% filter(p.adj <=0.01, logFC > 0.1) %>% pull(UniProt)
measured.in.plasma.name <- dap.res %>% filter(p.adj <=0.01, logFC > .1) %>% pull(Assay)

G <- as_tbl_graph(nw %>% transmute(from = uniprot_a,
                                   to = uniprot_b))
node_table <- as_tibble(G) %>% 
  left_join(dap.res %>% mutate(measured.as.soluble = T),
            by=c("name"="UniProt")) %>% 
  left_join(hpa_24.0 %>% transmute(gene, uniprot), 
            by=c("name"="uniprot")) %>% 
  mutate(protein_name = gene,
         measured.as.soluble = case_when(is.na(measured.as.soluble) ~F,
                                         .default = T))# %>%
(ligand_receptor_nw <- G %>% 
   inner_join(node_table,by="name") %>% 
   create_layout(layout = "fr") %>% 
   ggraph() + 
   geom_edge_link(alpha=.02) + 
   geom_edge_fan(width = .5, color = "grey90") +
   geom_node_point(aes(color=if_else(measured.as.soluble==T,logFC,NA),
                       size= if_else(measured.as.soluble==T,logFC,1))) +
   guides(color = guide_colourbar(barwidth = 3, barheight = .75),
          size=F) +
   labs(color="logFC of proteins\nin plasma") +
   scale_size(range=c(1,3.5)) +
   geom_node_text(aes(label = protein_name,
                      color= if_else(measured.as.soluble==T,logFC,NA)),
                  size=1, 
                  repel=T) +
   scale_color_continuous(low="thistle2",
                          high="darkred", 
                          guide="colorbar",
                          na.value="grey20") +
   theme_void() +
   theme(legend.position = "bottom",
         plot.title = element_text(size=6),
         legend.title = element_text( size=6),
         legend.text=element_text(size=6)) 
)

receptor_fam <- list(cxc_subfam = c("CXCR1","CXCR2","CXCR3","CXCR4","CXCR5","CXCR6","CXCR7","XCR1","CX3CR1"),
                     cc_subfam = paste0("CCR",1:11),
                     class1helicalcyto_fam = c("IL2RA","IL4R"),
                     class2helicalcyto_fam = c("IL10RA","IL10RB"),
                     prolaction_fam = c("GHR","CSF3R"),
                     ifn_fam =c("IFNAR1","IFNAR2","IFNGR1","IFNGR2"),
                     il1likecyto_fam = c("IL1R1","IL1RAP","IL1R2","IL18R1","IL18RAP","ST2","IL1RAP"),
                     nonclassified = c("CD4","CSF1R"),
                     tnf_fam = c("TNFR1","TNFR2","HVEM","FAS","DR4","DR5","DCR1","DCR2","EDAR","RANK","CD27","CD30","CD40","Ox40","TACI"),
                     tgfb_fam = c("TGFBR2","ACVR2B","ACVR1B")) %>% 
  enframe() %>% unnest(cols = c(value)) %>% dplyr::rename(subfam = name, receptor = value)
#extract all transmembrane receptors from CellPhoneDB as uniprotIDs

## filter CellPhoneDB protein_input for transmembrane & receptors
cpdb.receptor.transmem.name <- cpdb.protein_input %>% filter(transmembrane==T |
                                                               receptor==T) %>% 
  mutate(protein_name = gsub("_HUMAN","",protein_name)) %>% 
  pull(uniprot)
df <- pbmc_acute.avg.wide %>% 
  right_join(rna.markers.uniprot) %>% 
  filter(uniprot %in% nw$uniprot_b)

geneAnno <- df %>% transmute(gene,uniprot) %>% left_join(receptor_fam,by=c("gene"="receptor")) %>%
  mutate(subfam = ifelse(is.na(subfam),"Other",subfam),
         CPDB = ifelse(uniprot %in% cpdb.receptor.transmem.name,T,F),
         KEGG = ifelse(gene %in% receptor_fam$receptor,T,F),
         in_plasma = ifelse(gene %in% measured.in.plasma.name,T,F))


mat <- df %>% 
  dplyr::select(-uniprot) %>% 
  column_to_rownames("gene") %>% 
  as.matrix()

col.anno.df <- data.frame(colnames = colnames(mat)) %>% 
  transmute(colnames,
            colanno = case_when(grepl("DC",colnames) ~ "DC",
                                grepl("monocytes",colnames) ~ "Monocytes",
                                grepl("CD4",colnames) ~ "CD4+ T",
                                grepl("CD8",colnames) ~ "CD8+ T",
                                grepl("B|Plasma",colnames) ~ "B",
                                grepl("NK",colnames) ~ "NK",
                                grepl("gdT",colnames) ~ "gdT",
                                .default = "undefined"),
            colanno = factor(colanno, levels= c("DC","Monocytes","NK","gdT","B","CD4+ T","CD8+ T","undefined")))

colAnn.top <- HeatmapAnnotation(df = col.anno.df %>% column_to_rownames("colnames"), 
                                which = "col",
                                col = list(colanno = L1_colors),
                                show_annotation_name = F,
                                show_legend = F,
                                annotation_name_gp = gpar(fontsize=6),
                                annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                               title_gp = gpar(fontsize = 6),
                                                               direction = "horizontal",
                                                               legend_height = unit(.1, "cm"),
                                                               grid_width = unit(.2, "cm")),
                                simple_anno_size = unit(1, "mm")
)

Figure 3F

m <-  mat %>% 
  t() %>% 
  as.data.frame() %>% 
  mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% 
  as.matrix() 

(pbmc_l2_acute_cellphonedb_hm.wide <- m %>% 
   ComplexHeatmap::Heatmap(name="average\ngene\nexpression",
                           column_split = geneAnno$subfam, 
                           cluster_columns = T,
                           cluster_column_slices = T,
                           bottom_annotation = HeatmapAnnotation(df=geneAnno %>% transmute(in_plasma),
                                                                 which="column",
                                                                 annotation_legend_param = list(title_gp = gpar(fontsize = 6), 
                                                                                                labels_gp = gpar(fontsize = 6)),
                                                                 annotation_name_gp = gpar(fontsize = 5),
                                                                 simple_anno_size = unit(1.5, "mm"),na_col = c("white","white","white"),
                                                                 show_legend = c(FALSE,FALSE,FALSE),
                                                                 gp = gpar(col = "grey90"),
                                                                 col=list(CPDB = c("TRUE" = "grey60", "FALSE" = "white","NA" = "white"),
                                                                          KEGG = c("TRUE" = "grey60", "FALSE" = "white","NA" = "white"),
                                                                          in_plasma = c("TRUE" = "darkred", "FALSE" = "white","NA" = "white"))),
                           show_row_dend = F,
                           row_title_side = "right",
                           row_title_rot = 0,
                           row_title_gp = gpar(fontsize = 5),
                           row_title = NULL,
                           col = scaled_01_col,
                           row_names_gp = gpar(fontsize = 4),
                           show_column_dend = T,
                           column_dend_height = unit(2,"mm"),
                           row_dend_width = unit(2, "mm"), 
                           row_dend_side = "left",
                           clustering_method_columns = "mcquitty",
                           right_annotation = rowAnnotation(df = col.anno.df %>% column_to_rownames("colnames"), 
                                                            
                                                            col = list(colanno = L1_colors),
                                                            show_annotation_name = F,
                                                            show_legend = F,
                                                            annotation_name_gp = gpar(fontsize=6),
                                                            annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                                                           title_gp = gpar(fontsize = 6),
                                                                                           direction = "horizontal",
                                                                                           legend_height = unit(.1, "cm"),
                                                                                           grid_width = unit(.2, "cm")),
                                                            simple_anno_size = unit(1, "mm")
                           ),
                           cluster_rows = F,
                           row_split = col.anno.df$colanno,
                           column_title_gp = gpar(fontsize=4),
                           column_title_rot = 45,
                           column_names_gp = gpar(fontsize = 4), 
                          heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                  title_gp = gpar(fontsize = 6),
                                  grid_width = unit(3, "mm")))
)

Supplemantary Figure S6

related to main Figure 3

Figure S6A

(rhapsody_cells_per_sample <- tibble(pbmc@meta.data) %>%
  #as.data.table %>% # the resulting md object has one "row" per cell
  rownames_to_column("CellID")  %>% 
  group_by(orig.ident,Time) %>% 
  dplyr::count() %>% 
  ggplot(aes(x=orig.ident,y=n, fill=Time)) +
  scale_fill_manual(values = TIME_colors,breaks = c("Acute","D10","Y1")) +
  scale_y_continuous(expand = c(0,0), trans = "sqrt") +
  coord_flip()+
  geom_bar(stat="identity", position="dodge", show.legend = TRUE) +
  geom_hline(yintercept=6000,lwd=.2) +
  labs(y="Number of cells",
       x="",
       fill="") + 
  theme_minimal())

Figure S6B

## integration
(rhapsody_umap_ggplot_int_orig.ident <- rhapsody_umap_coords %>% 
  ggplot(aes(x = wnnUMAP_1, y = wnnUMAP_2)) + 
  geom_point(aes(color = as.character(orig.ident)), size = 0.1, alpha=.1) +
  labs(x = 'wnnUMAP 1', y = 'wnnUMAP 2', color=NULL)  + 
  guides(color = guide_legend(override.aes = list(alpha = 1,size=.25))) +
  my_dimred_theme
)

Figure S6C

## integration
(rhapsody_umap_ggplot_int_time <- rhapsody_umap_coords %>% 
  ggplot(aes(x = wnnUMAP_1, y = wnnUMAP_2)) + 
  geom_point(aes(color = as.character(Time)), size = 0.25, alpha=.1) +
  labs(x = 'wnnUMAP 1', y = 'wnnUMAP 2', color=NULL)  + 
  scale_color_manual(values = TIME_colors,breaks = c("Acute","D10","Y1")) +
  guides(color = guide_legend(override.aes = list(alpha = 1,size=.25))) +
  my_dimred_theme
)

Figure S6D

(vln_adt.weight <- VlnPlot(pbmc, features = "adt.CCA.weight", group.by = 'CellType_L2', cols = L2_colors, sort = TRUE, pt.size = 0) +
  NoLegend() + 
  labs(title = "adt weight", y="ADT weight",x=NULL))

Figure S6E

rna.marker4dotplot <- c("S100A12","CD14","S100A9","VMO1","C1QA","FCGR3A", "KLRF1","KIR2DL1",
                        "GNLY","IL12RB2","IL18R1","GZMK","TYMS","TOP2A", "KIAA0101","CCR7","LEF1",
                        "MYC", "PASK","CD28","ICOS","RGS1","CTLA4","CCR5","LAG3","POU2AF1",
                        "FOXP3","IL2RA","CD8A","ZNF683","RORC","IKZF2","MS4A1","CD79A","IGKC",
                        "TCL1A","FCER2","CD200","TNFRSF17","FCER1A","CLEC10A","CD1C","NRP1","TLR9","TLR7")

(dotplot.rna <- DotPlot(pbmc,
        features = rna.marker4dotplot,
        assay = "RNA",
        cols = c("RdYlBu"),
        col.min = -2.5,
        col.max = 2.5,
        dot.min = 0,
        dot.scale = 1,
        idents = NULL,
        group.by = NULL,
        split.by = NULL,
        cluster.idents = F,
        scale = TRUE,
        scale.by = "radius",
        scale.min = NA,
        scale.max = NA) + 
  RotatedAxis() + 
  theme(axis.text.x=element_text(size=6), 
        axis.text.y=element_text(size=6),
        text = element_text(size=6)) + 
  labs(x="",y="", title="mRNA expression")
)

DotPlot(pbmc,
        features = rownames(pbmc@assays$ADT),
        assay = "ADT",
        cols = c("RdYlBu"),
        col.min = -2.5,
        col.max = 2.5,
        dot.min = 0,
        dot.scale = 1,
        idents = NULL,
        group.by = NULL,
        split.by = NULL,
        cluster.idents = F,
        scale = TRUE,
        scale.by = "radius",
        scale.min = NA,
        scale.max = NA) + 
  theme(axis.text.x=element_text(size=6), # cell subsets
        axis.text.y=element_text(size=6),
        text = element_text(size=6)) + 
  RotatedAxis() +
  labs(x="",y="", title="Surface protein expression")

Figure S6F

(cellnumbers_l2 <- tibble(pbmc_acute@meta.data) %>% 
   group_by(CellType_L2) %>% 
   count() %>% 
   
   ggplot(aes(fill = CellType_L2, y=n, x=fct_reorder(CellType_L2,n))) + 
   geom_col(show.legend = F) +
   scale_fill_manual(values = L2_colors) +
   scale_y_continuous(expand = c(0, 0),trans  = "log10", breaks=c(1,10,100,1000,5000)) + 
   coord_flip() +
   labs(x=NULL,
        y="Number of cells") +
   theme_bw() +
   theme(panel.grid.major = element_blank(),
         panel.border = element_blank()))

Figure S6G

genes.oi.timepoints = VlnPlot(pbmc,
                              features = c("CD163", "IL1B", "IL1RN", "ICAM1", "LILRB4", "CXCL10", "S100A12",  "NAMPT",
                                           "CCL2", "CXCL11", "CXCL9", "AZU1","VMO1", "TNFRSF8", "CHI3L1","CCL4", "GZMA",
                                           "GZMB","GZMH","CST7","TNFRSF9","IL2RA","IL1RL1","CD48", "CD27", "CD38", "HAVCR2"),
                              group.by = 'CellType_L2', assay = "RNA",
                              split.by = "Time", cols = time3_col, sort = F, pt.size = 0,stack = T,flip = F) +
  theme(axis.text.x = element_text(angle = 0, size=6),
        axis.text.y = element_text(size=6),
        strip.text.x = element_text(angle = 90, size = 5, face=NULL,hjust = .5),
        axis.title.y = element_blank(),
        axis.title.x = element_text(size=6),
        # strip.text.y = element_text(size = 6),
        # strip.text.x = element_text(size=6),
        legend.position = "right",
        legend.key.size = unit(.2, 'cm'), #change legend key size
        legend.key.height = unit(.2, 'cm'), #change legend key height
        legend.key.width = unit(.2, 'cm'), #change legend key width
        legend.title = element_text(size=5), #change legend title font size
        legend.text = element_text(size=5))

genes.oi.timepoints$layers[[1]]$aes_params$size = .1
genes.oi.timepoints

Supplementary Figure 7

related to main Figure 3

dooley <- readRDS("../data/data/ReAnalysis_DooleyNL_etal_bioRxiv_2022/annotated_Sabah_data_21Oct2022.rds")

dooley_colors <- setNames(randomcoloR::distinctColorPalette(length(unique(dooley@meta.data$celltype))),
                          unique(dooley@meta.data$celltype))
## Preliminary QC check

tibble(dooley@meta.data) %>% # the resulting md object has one "row" per cell
  rownames_to_column("CellID")  %>% 
  group_by(orig.ident,timepoint,sample.day,ID) %>% 
  dplyr::count() %>% 
  ungroup() %>% 
  ggplot(aes(x=fct_reorder(orig.ident, timepoint),y=n, fill=ID)) +
  scale_y_continuous(expand = c(0, 0)) +
  coord_flip()+
  geom_bar(stat="identity", position="dodge", show.legend = F) +
  labs(title = "Number of cells per sample",
       x=NULL) +
  theme_minimal()

Figure S7A

dooley_umap_coords <- data.table::data.table(dooley@meta.data, Embeddings(object = dooley, reduction = 'umap')) %>% rownames_to_column("CellID") 

lable_df <- dooley_umap_coords %>%
  dplyr::group_by(celltype) %>%
  dplyr::select(celltype, contains("UMAP")) %>%
  summarise_all(mean)

(dooley_umap_ggplot <- dooley_umap_coords %>% 
    ggplot(aes(x = UMAP_1, y = UMAP_2)) + 
    geom_point(aes(color = as.character(celltype)), size = 0.1, alpha=.5,show.legend = F) +
    ggrepel::geom_text_repel(data=lable_df,aes(x=UMAP_1,y=UMAP_2, label=celltype),size=2) +
    labs(x = 'UMAP 1', y = 'UMAP 2')  + 
    scale_color_manual(values=dooley_colors) +
    my_dimred_theme)

Figure S7B

## Percentage celltype in sample
(dooley_per_sample_perc <- tibble(dooley@meta.data) %>% 
   group_by(timepoint,orig.ident) %>% 
   count(celltype) %>% 
   # Stacked + percent
   ggplot(aes(fill = celltype, y=n, x=orig.ident)) + 
   geom_bar(position="fill", stat="identity",width = 0.9) +
   facet_grid(~timepoint,scales = "free_x",space = "free_x") +
   scale_y_continuous(labels = scales::percent) + 
   scale_fill_manual(values=dooley_colors) +
   scale_y_continuous(labels = scales::percent,expand = c(0,0)) + 
   labs(x = "",
        y = "Frequency",
        fill="") +
   theme_minimal() +
   theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
         legend.text = element_text(size=6),
         legend.position = "top",
         panel.grid.major = element_blank()))

get only acute malaria cells (Day0)

dooley_0 <- subset(dooley, subset=timepoint=="Day0")
#- RNA Normalization
dooley_0 <- NormalizeData(object = dooley_0, assay = 'RNA', normalization.method = 'LogNormalize', scale.factor = 10000)

Figure S7C

(dooley_0_cellnumbers <- 
   tibble(dooley_0@meta.data) %>% 
   group_by(celltype) %>% 
   count() %>% 
   ggplot(aes(fill = celltype, y=n, x=fct_reorder(celltype,n))) + 
   geom_col(show.legend = F) +
   scale_y_continuous(expand = c(0, 0),trans  = "log10") +
   coord_flip() +
   scale_fill_manual(values=dooley_colors) +
   labs(x=NULL,
        y="Number of cells") +
   theme_bw() +
   theme(panel.grid.major = element_blank(),
         panel.border = element_blank()))

## calculation of pseudobulk, for each identity based on count data
dooley_0.avg.wide <- log1p(AverageExpression(dooley_0, group.by = "celltype", slot = "counts", verbose = FALSE)$RNA) %>% 
  as.data.frame() %>% 
  rownames_to_column("gene") 

dooley_0.avg.long <- dooley_0.avg.wide %>% 
  pivot_longer(names_to = "celltype", values_to = "avgExp",cols = -gene) %>% filter(avgExp >0)
dooley.gene.match <- full_mapping %>% 
  filter(UniProt %in% wilcoxUp) %>% 
  filter(Symbol %in% unique(dooley_0.avg.long$gene))

mat_dooley_0 <- dooley_0.avg.wide %>% 
  filter(gene %in% dooley.gene.match$Symbol) %>% 
  column_to_rownames("gene") %>% 
  as.matrix() 

Figure S7D

## Rhapsody vs. Dooley
##binning of cell immune cell subsets

#dim(mat_dooley_0)
#dim(mat_pbmc_acute)

## gene overlap Rhapsody, Dooley et al, Explore
rhapsody_dooley_overlapp <- intersect(rownames(mat_dooley_0),rownames(mat_pbmc_acute))

compare_dooley_rhapsody <- data.frame(mat_dooley_0[rhapsody_dooley_overlapp,]) %>% 
  rownames_to_column("gene") %>%
  pivot_longer(cols = -gene) %>%
  mutate(origin = "dooley") %>% 
  bind_rows(
    data.frame(mat_pbmc_acute[rhapsody_dooley_overlapp,]) %>% 
      rownames_to_column("gene") %>% 
      pivot_longer(cols = -gene) %>%
      mutate(origin = "rhapsody")) %>%
  
  
  mutate(name.common = ifelse(grepl("CD14",name),"CD14mono",
                              ifelse(grepl("CD16.monocytes",name,ignore.case = T),"CD16mono",
                                     ifelse(grepl("pDC",name),"pDC",
                                            ifelse(grepl("mDC",name),"mDC",
                                                   ifelse(grepl("NKT",name),"NKT",
                                                          ifelse(grepl("gdT|γδ.T.cells",name),"gdTcell",
                                                                 ifelse(grepl("CD8",name),"CD8T",
                                                                        ifelse(grepl("CD4",name),"CD4T",
                                                                               ifelse(grepl("NK",name),"NK",
                                                                                      ifelse(grepl("B",name),"Bcell",
                                                                                             ifelse(grepl("Unknown|undefined",name),"undefined",
                                                                                                    name)))))))))))) 
common.celltypes <- intersect(filter(compare_dooley_rhapsody,origin=="dooley") %>% pull(name.common),
                              filter(compare_dooley_rhapsody,origin=="rhapsody") %>% pull(name.common))

dooley_hm <- compare_dooley_rhapsody %>% 
  filter(origin=="dooley", name.common %in% common.celltypes) %>% 
  pivot_wider(names_from = gene, values_from = value,id_cols = name.common) %>% 
  column_to_rownames("name.common") %>% 
  ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% 
    as.matrix() %>% 
    t() %>%

  Heatmap(name="Dooley",
          column_title = "Dooley et al.",
          column_title_gp = gpar(fontsize=6),
          
          column_order = common.celltypes,
          col = scaled_01_col,
          cluster_rows = TRUE,
          row_dend_reorder = TRUE,
          show_row_names = TRUE,
          show_heatmap_legend = F,
          row_title_gp = gpar(fontsize = 5),
          row_title_rot = 0,
          row_names_gp = gpar(fontsize = 4),
          row_dend_width = unit(5, "mm"), 
          column_names_gp = gpar(fontsize = 5), 
          column_names_rot = 90,
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 5),
                                      title_gp = gpar(fontsize = 5)),
          width = nrow(.)*unit(.3, "mm"), 
          height = ncol(.)*unit(6, "mm"),
  )

rhapsody_hm <- filter(compare_dooley_rhapsody, origin=="rhapsody", name.common %in% common.celltypes) %>%
  pivot_wider(names_from = gene, values_from = value,id_cols = name.common,values_fn = median) %>% 
  column_to_rownames("name.common") %>% 
  ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% #scale(.))) %>% 
    as.matrix() %>% 
    t() %>%

  Heatmap(name="average\ngene\nexpression",
          column_title = "This study",
          column_title_gp = gpar(fontsize=6),
          column_order = common.celltypes,
          col = scaled_01_col,
          cluster_rows = TRUE,
          row_dend_reorder = TRUE,
          show_row_names = TRUE,
          row_title_gp = gpar(fontsize = 5),
          row_title_rot = 0,
          row_names_gp = gpar(fontsize = 4),
          row_dend_width = unit(5, "mm"), 
          column_names_gp = gpar(fontsize = 5), 
          column_names_rot = 90,
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 5),
                                      title_gp = gpar(fontsize = 5),
                                       title_position = "topcenter"
          ),
          width = nrow(.)*unit(.3, "mm"), 
          height = ncol(.)*unit(6, "mm"),
  )

compare_dooley_rhapsody_hm_new <- dooley_hm + rhapsody_hm

draw(compare_dooley_rhapsody_hm_new, row_dend_side = "left", main_heatmap = "average\ngene\nexpression",auto_adjust = F)

Figure S7E

dim(mat_dooley_0)
## [1] 208  15
row.anno.df <- data.frame(Assay = rownames(mat_dooley_0)) %>% 
  left_join(dap.res,by=c("Assay")) %>% 
  left_join(hpa_24.0,by=c("Assay"="gene")) %>% 
  mutate(secretome_function = ifelse(is.na(secretome_function),"Not secreted", secretome_function)) %>% 
  filter(secretome_function != "Not secreted")

rowAnno <- HeatmapAnnotation(df = row.anno.df %>% transmute(Assay,secretome_location) %>% column_to_rownames("Assay"),
                             which = "row", 
                             show_legend = c(TRUE), 
                             show_annotation_name = F,
                             annotation_name_gp = gpar(fontsize = 5),
                             annotation_legend_param = list(title = "HPA\nclassification",
                                                            title_gp = gpar(fontsize = 5), 
                                                            labels_gp = gpar(fontsize = 5),
                                                            direction="horizontal",
                                                            legend_height = unit(1, "mm"), 
                                                            grid_width = unit(3, "mm"),
                                                            title_position = "topleft"),
                             col = list(secretome_location = secretome_location_cols),
                             simple_anno_size = unit(3, "mm"),
                             na_col = "grey90")

(dooley_day0_hm.hpa.mapping <- mat_dooley_0[row.anno.df$Assay,] %>% 
    t() %>% 
    ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% 
    as.matrix() %>% 
    t() %>% 
    ComplexHeatmap::Heatmap(
      name="average\ngene\nexpression\n",
      col = scaled_01_col,
      right_annotation = rowAnno,
      column_dend_height = unit(2, "mm"), 
      cluster_rows = TRUE,
      row_dend_reorder = TRUE,
      show_row_names = TRUE,
      row_split = row.anno.df$secretome_function,
      row_title_side = "right",
      row_title_gp = gpar(fontsize = 5),
      row_title_rot = 0,
      row_names_gp = gpar(fontsize = 4),
      row_dend_width = unit(4, "mm"), 
      column_names_gp = gpar(fontsize = 5), 
      column_names_rot = 90,
      heatmap_legend_param = list(labels_gp = gpar(fontsize = 5),
                                  title_gp = gpar(fontsize = 5)),
      height = ncol(.)*unit(8, "mm"),
      width = ncol(.)*unit(2,"mm"))
)

Figure S7F

mat_dooley_0 <- dooley_0.avg.wide %>% 
  filter(gene %in% dooley.gene.match$Symbol) %>% 
  column_to_rownames("gene") %>% 
  as.matrix() 

dim(mat_dooley_0)
## [1] 208  15
row.anno.df <- data.frame(Assay = rownames(mat_dooley_0)) %>% 
  left_join(dap.res,by=c("Assay")) %>% 
  left_join(hpa_24.0,by=c("Assay"="gene")) %>% 
  mutate(secretome_function = ifelse(is.na(secretome_function),"Not secreted", secretome_function)) %>% 
  filter(secretome_function == "Not secreted")


(dooley_day0_hm.no.hpa.mapping <- mat_dooley_0[row.anno.df$Assay,] %>% 
    t() %>% 
    ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% #scale(.))) %>% 
    as.matrix() %>% 
    t() %>% 
    ComplexHeatmap::Heatmap(name="average\ngene\nexpression",
                            col = scaled_01_col,
                            show_heatmap_legend = F,
                            column_dend_height = unit(2, "mm"), 
                            cluster_rows = TRUE,
                            row_dend_reorder = TRUE,
                            show_row_names = TRUE,
                            row_split = row.anno.df$secretome_function,
                            row_title_side = "right",
                            row_title_gp = gpar(fontsize = 5),
                            row_title_rot = 0,
                            row_names_gp = gpar(fontsize = 4),
                            row_dend_width = unit(4, "mm"), 
                            column_names_gp = gpar(fontsize = 5), 
                            column_names_rot = 90,
                            heatmap_legend_param = list(labels_gp = gpar(fontsize = 5),
                                                        title_gp = gpar(fontsize = 5)),
                            height = ncol(.)*unit(8, "mm"),
                            width = ncol(.)*unit(2,"mm"))
)

Figure 4

Protein profile-based patient stratification of disease severity

Supplementary Figure 8

** related to main Figure 4**

Figure S8A

clin_marker_cols <- c("CRP","Creatinine","Parasitemia","Platelets","Bilirubin","ASAT","ALAT","Hemoglobin")

clin_marker_cols <- setNames(brewer.pal(length(clin_marker_cols),name="Set3"), clin_marker_cols)



clinical_variables_4circos <-  subjectTable %>% 
    left_join(clinchem_study_pats_acute.wide, by="study_id") %>% 
    #inner_join(patient_clust,by="study_id") %>% 
    ungroup() %>% 
    pivot_longer(cols = c(plt_count_min,inf_rbc_max,crp_max,hb_min,bili_max,crea_max,"p_alat","p_asat"),
                 names_to = "clin.var", values_to="clin.val",
    ) %>% 
    drop_na(clin.val) %>% 
    group_by(clin.var) %>% 
 mutate(n_group= as.character(n()),
           label_group= factor(paste0('\n n = ', n_group))) %>% 
    mutate(clin.var = case_when(clin.var=="crp_max"~"CRP",
                          clin.var=="p_alat"~"ALAT",
                          clin.var=="p_asat"~"ASAT",
                          clin.var=="plt_count_min"~"Platelets",
                          clin.var=="inf_rbc_max" ~"Parasitemia",
                          clin.var=="bili_max"~"Bilirubin",
                          clin.var=="hb_min" ~"Hemoglobin",
                          clin.var=="crea_max"~"Creatinine",
                          .default=clin.var)) %>% 
    mutate(clin.var = factor(clin.var, levels=names(clin_marker_cols))) 
 
(clin_para_whole_cohort <- clinical_variables_4circos %>% 
    ggplot(aes(x=label_group, y=clin.val, fill=clin.var)) +
    geom_violin(trim=F, show.legend = F, width=.4,lwd=.25) +
    geom_jitter(size=0.05,width = .1, show.legend = F,lwd=.25) +
    geom_boxplot(alpha=.7, outlier.shape = NA, width=.2, show.legend = F,lwd=.25) +
    facet_wrap(~clin.var, scales = "free", nrow = 4,
    labeller = labeller(clin.var = c("Bilirubin"= "Bilirubin\n(\U003BCmol/L)",
                                     "ALAT"="ALT\n(U/L)",
                                     "ASAT"="AST\n(U/L)",
                                     "CRP"="CRP\n(mg/L)",
                                     "Parasitemia"="Parasitemia\n(%)", 
                                     "Creatinine"="Creatinine\n(\U003BCmol/L)",
                                     "Hemoglobin"="Hemoglobin\n(g/dL)",
                                     "Platelets"="Platelet\n(counts)"))) +
    theme_bw(base_size = 6)+
    labs(y="Clinical parameter value",
         x=NULL) +
  scale_fill_manual(values=clin_marker_cols))

Figure S8C

patient_SOFA <- subjectTable %>% dplyr::select(study_id, contains("SOFA"))

who22_severemalaria <- subjectTable %>% 
  transmute(study_id,
            respiratory_distress = case_when(pulm_edema == 1 |
                                               resp_distress == 1 |
                                               ards == 1 ~ 1, 
                                             .default = 0),
            circ_80,
            hb_70 = case_when(hb_min <= 70 ~ 1, 
                              hb_min >70 ~0,
                              .default = NA),
            bili_50,
            crea_265 = case_when(crea_max >= 265 ~ 1, 
                                 crea_max <265 ~ 0,
                                 .default = NA),
            parasitaemia_2 = case_when(inf_rbc_max >= 2 ~ 1,
                                       inf_rbc_max < 2 ~ 0,
                                       .default = NA),
            parasitaemia_5 = case_when(inf_rbc_max >= 5 ~ 1,
                                       inf_rbc_max < 5 ~ 0,
                                       .default = NA)
  )

mat <- who22_severemalaria %>% 
  column_to_rownames("study_id") %>% 
  as.matrix() %>% 
  t()

mat_sofa_total <- data.frame(study_id = colnames(mat)) %>% 
  left_join(patient_SOFA, by="study_id") 

study_id_SOFA.sorted <- mat_sofa_total %>% arrange(-SOFA_total) %>% pull(study_id)

mat <- mat[,study_id_SOFA.sorted]


severesign_count <- who22_severemalaria %>% 
  transmute(study_id,
            respiratory_distress,
            circ_80,
            hb_70,
            bili_50,
            crea_265,
            parasitaemia_5) %>% 
  replace(is.na(.), 0) %>% 
  rowwise() %>%
  mutate(nr_of_severe_signs = sum(c_across(where(is.numeric)))) %>% 
  transmute(study_id,
            nr_of_severe_signs) 

(hm.sofa.clin <- mat %>% 
  Heatmap(name = "Severe malaria symptoms\ndefined by WHO 2015",
          col = c("0"="white","1"="#C51B7D"),
          column_names_gp = gpar(fontsize = 6), 
          na_col = "grey90",
          cluster_columns = F,
          cluster_rows = F,
          show_row_dend = F, 
          show_column_dend = F,
          show_column_names = F,
          top_annotation = HeatmapAnnotation(df = data.frame(study_id = colnames(mat)) %>%
                                               left_join(severesign_count) %>%
                                               column_to_rownames("study_id"),
                                             gp = gpar(fontsize=6),
                                             annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                                            title_gp = gpar(fontsize = 6),
                                                                            direction = "horizontal",
                                                                            title_position = "topcenter",
                                                                            title = "Nr of\nsevere malaria\nsymptoms"),
                                             simple_anno_size = unit(2, "mm"),
                                             annotation_name_gp = gpar(fontsize=6),
                                             col = list(nr_of_severe_signs = circlize::colorRamp2(c(0,6), c("white","orange")))),
          row_title_side = "left",
          row_title_rot = 0,
          row_title_gp = gpar(fontsize = 6),
          column_title_side = "top",
          row_names_gp = gpar(fontsize = 6),
          row_dend_width = unit(0.5, "cm"), 
          column_title_gp = gpar(fontsize = 6),
          column_names_rot = 90,
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                      title_gp = gpar(fontsize = 6), 
                                      title_position = "topcenter",
                                      at = c(0,1),
                                      labels = c("no","yes")),
          bottom_annotation = HeatmapAnnotation(df = data.frame(study_id = colnames(mat)) %>% 
                                left_join(patient_SOFA, by="study_id") %>% 
                                dplyr::select(-study_id) %>% 
                                as.data.frame(),
                              which = 'col', 
                              gp = gpar(fontsize=6),
                              simple_anno_size = unit(2, "mm"),
                              annotation_name_gp = gpar(fontsize=6),
                              col = list(SOFA_total = colorRamp2(c(min(patient_SOFA$SOFA_total,na.rm = TRUE),
                                                                   median(patient_SOFA$SOFA_total,na.rm = TRUE),
                                                                   max(patient_SOFA$SOFA_total,na.rm = TRUE)),
                                                                 c(brewer.pal(3,name="PuBu"))),
                                         SOFA_liver = SOFA_sub_col,
                                         SOFA_cns = SOFA_sub_col,
                                         SOFA_coag = SOFA_sub_col,
                                         SOFA_resp = SOFA_sub_col,
                                         SOFA_cardio = SOFA_sub_col,
                                         SOFA_renal = SOFA_sub_col),
                              show_legend = c(T,F,F,F,F,F), 
                              annotation_legend_param = list(SOFA_total = list(title = "SOFA (total)",
                                                                               labels_gp = gpar(fontsize = 6),
                                                                               title_gp = gpar(fontsize = 6),
                                                                               direction = "horizontal",
                                                                               title_position = "topcenter"
                                                                               ),
                                                             SOFA_cns = list(title="SOFA (subcategorical)",
                                                                             labels_gp = gpar(fontsize = 6),
                                                                             title_gp = gpar(fontsize = 6),
                                                                             direction = "horizontal",
                                                                             title_position = "topcenter"))),
          width = ncol(.)*unit(1.3, "mm"), 
          height = nrow(.)*unit(1.6, "mm"),
          rect_gp = gpar(col = "grey80", lwd = .2),
          border_gp = gpar(col = "black", lty = .5)))

Figure S8D-E

data4_pcaRes_FCmedian <- fc_over_median_M12 %>% 
  filter(Assay %in% c(dap.res %>% filter(FDR==TRUE, abs(logFC)>1) %>% pull(Assay))) %>% 
  pivot_wider(values_from = dNPX, names_from = Assay, id_cols = study_id) %>% column_to_rownames("study_id") 

## PC calculation
pcaRes_FCmedian <- prcomp(data4_pcaRes_FCmedian, center = TRUE, scale. = TRUE)

varExp_FCmedian <- round(pcaRes_FCmedian$sdev^2 / sum(pcaRes_FCmedian$sdev^2) * 100)

#sum(varExp_FCmedian[1:6])

pcaDF_FCmedian <- data.frame(pcaRes_FCmedian$x) %>% 
  rownames_to_column("study_id") %>% dplyr::select(1:10) %>% 
  inner_join(data4_pcaRes_FCmedian %>% rownames_to_column("study_id"), by="study_id")

(pca_FCmedian <- pcaDF_FCmedian %>% 
    ggplot(aes(x=PC1,y=PC2)) +
    geom_point(size=.5) + 
    my_dimred_theme +
    coord_fixed(ratio = 1.75) +
    labs(x=paste0("PC1 (",varExp_FCmedian[1],"%)"),
         y=paste0("PC2 (",varExp_FCmedian[2],"%)"),
         title = "dNPX (delta NPX of acute over convalescence median)",
         caption = paste0("# samples: ",dim(data4_pcaRes_FCmedian)[1],
                          "\n # proteins: ",dim(data4_pcaRes_FCmedian)[2],
                          "\nlogFC>1")
    ))

(acute.dnpx.ellbow <- data.frame(PC = 1:10,
           varExp = varExp_FCmedian[1:10]) %>% 
  ggplot(aes(x=PC, y=varExp)) +
  scale_y_continuous(breaks = seq(0, 35, by = 5)) +
  geom_point(size=.2) +
  geom_line(lwd=.2) +
  theme_minimal() +
  scale_x_continuous(limits=c(1,10), breaks = c(1:10)))

df <- pcaDF_FCmedian %>% 
  dplyr::select(study_id,PC1:PC6) %>% 
  column_to_rownames("study_id") 

set.seed(2023L)
km <- kmeans(df, centers = 3, nstart = 25) 

km.res <- data.frame(study_id = rownames(df)) %>% inner_join(data.frame(cluster = km$cluster) %>% rownames_to_column("study_id"), by="study_id") 
patient_clust <- km.res %>%
  inner_join(subjectTable %>% transmute(study_id, SOFA_total),by="study_id") %>% 
  group_by(cluster) %>% 
  summarise(meanSOFA_total = mean(SOFA_total)) %>% 
  arrange(-meanSOFA_total) %>% 
  mutate(severity_lab = c("severe","moderate","mild")) %>% 
  rownames_to_column("rowname") %>% 
  mutate(rowname = as.numeric(rowname)) %>% 
  left_join(km.res %>% transmute(study_id,cluster)) %>% 
  mutate(cluster.orig =  fct_reorder(as.factor(cluster),rowname),
         severity_lab = fct_reorder(as.factor(severity_lab),rowname),
         cluster = fct_reorder(as.factor(rowname),rowname))

patient_clust %>% write_tsv(file = paste0(result.dir,"PatientClustering.tsv"))
patient_clust %>% saveRDS(file = paste0(result.dir,"PatientClustering.rds"))

Figure S8D-F

pca_FCmedian

acute.dnpx.ellbow

(pcaDF_FCmedian_PC1_6_hm <- pcaDF_FCmedian %>% 
  dplyr::select(study_id,PC1:PC6) %>% 
  column_to_rownames("study_id") %>% 
  t() %>% 
  Heatmap(name="PC value",
          column_km = 3,
          show_column_names = F,
          row_names_gp = gpar(fontsize=6),
          row_dend_width = unit(3, "mm"), 
          column_dend_height = unit(6,"mm"),
          column_title_gp = gpar(fontsize = 6), 
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                      title_gp = gpar(fontsize = 6),
                                      legend_height = unit(1, "mm"), 
                                      title_position = "topcenter"))
)

Figure S8G

df_acute_patclust_incl_conv <- data.long %>% 
  inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),by="sample_id") %>% 
  inner_join(patient_clust,by="study_id") %>% 
  
  filter(Time=="Acute") %>% 
  ## adding data for M12 time point
  bind_rows(data.long %>% 
              inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),by="sample_id") %>% 
              inner_join(patient_clust,by="study_id") %>% 
              filter(Time=="M12") %>% 
              mutate(severity_lab = "convalescence")) %>% 
  mutate(severity_lab = factor(as.factor(severity_lab),
                               levels=c("severe","moderate","mild","convalescence"),
                               labels=c("severe","moderate","mild","convalescence"))) 
my_comparisons_severe_conv <- list(c("severe", "moderate"), c("moderate", "mild"), c("severe", "mild"),c("mild","convalescence"))

(liver.tissueleakage.severity.plot <- df_acute_patclust_incl_conv %>%
  filter(Assay %in% c("AGXT","HAO1")) %>% 
  ggplot(aes(x=severity_lab, y=NPX, color=severity_lab, fill=severity_lab)) + 
  geom_violin(trim = F,alpha=.9) +
  geom_jitter(size=0.25,show.legend = F, width = 0.05, alpha=1, color="grey20") +
  geom_boxplot(alpha=.7,width=0.25,outlier.shape = NA,color="black", fatten = 2,lwd=.25,show.legend = F) +
  stat_compare_means(method = "wilcox.test",
                     label.sep = "\n",
                     hide.ns = T,
                     label = "p.signif" ,
                     vjust = .5,
                     size=2,
                     lwd = .2,
                     comparisons =my_comparisons_severe_conv,
                     show.legend = F) +
  facet_wrap(~Assay,ncol = 8,scales = "free_y") +
  theme_minimal() +
  theme(legend.position="bottom",
        axis.text.x = element_blank()) +
  labs(x="",
       color=NULL,
       fill=NULL) +
  scale_color_manual(values= c(patient_kclust3_lab_conv)) + 
    scale_fill_manual(values= c(patient_kclust3_lab_conv))
)

Figure 4A

(acute.dnpx.pca.clustered <- pcaDF_FCmedian %>% 
  inner_join(patient_clust) %>% 
  ggplot(aes(x=PC1,y=PC2, color=cluster)) +
  geom_point(size=.5) +
    scale_color_manual(values=patient_kclust3) +

  labs(color="Cluster",
       title="dNPX") +
  coord_equal(ratio = 1.5)  + theme_minimal())

acute.dnpx.pca.clustered


 ggExtra::ggMarginal(acute.dnpx.pca.clustered, type="density",groupColour = TRUE, groupFill = TRUE)

Figure 4B

my_comparisons <- list(c("1", "2"), c("2", "3"), c("1", "3"))

(clusters_sofa <- subjectTable %>% 
    inner_join(patient_clust,by="study_id") %>% 
    
    ggplot(aes(x=cluster, y=SOFA_total, color=cluster, fill=cluster)) +
    geom_jitter(width = 0.2,show.legend = T, size=0.5,alpha=.7) +
    geom_boxplot(alpha=1,width=0.3,color="black",outlier.colour = NA, fatten = 2,lwd=.25,show.legend = F) +
    labs(title = paste0("Sequential Organ Failure Assessment (SOFA) score")) + 
    scale_color_manual(values=patient_kclust3)+
    scale_fill_manual(values=patient_kclust3) +
    scale_y_continuous(limits = c(0,16)) +
    stat_compare_means(method = "wilcox.test",
                       label.sep = "\n",
                       hide.ns = T,
                       label = "p.signif" ,
                       vjust = .5,
                       size=2,
                       lwd = .2,
                       comparisons =my_comparisons) +
    theme_minimal()+
    theme(legend.position ="none"))

Figure 4C

prot.data.4.corr <- data.long %>%
  inner_join(dap.res,by=c("Assay", "UniProt")) %>% 
  filter(p.adj<=0.05,
         abs(logFC)>1,
  ) %>% 
  pivot_wider(values_from = NPX, names_from = Assay,id_cols = sample_id) %>% 
  inner_join(sampleTable_simple %>% filter(Time=="Acute") %>% transmute(sample_id,study_id), by="sample_id") %>%
  dplyr::select(-sample_id) %>% 
  dplyr::select(study_id, everything()) 


clinical.feat.list <- c("inf_rbc_max", "resp_rate_max","sat", "syst_bp_min",
                        "p_alat", "p_asat",
                        "hb_min","wbc_count","plt_count_min","crp_max","bili_max","crea_max","SOFA_cns","SOFA_liver","SOFA_renal","SOFA_coag","SOFA_resp","SOFA_total")
  
clin.data.4.corr <-
  subjectTable %>% 
      left_join(clinchem_study_pats_acute.wide, by="study_id") %>% 

  dplyr::select(study_id, all_of(clinical.feat.list))


my_comparisons_severe <- list(c("severe", "moderate"), c("moderate", "mild"), c("severe", "mild"))

df <- clin.data.4.corr %>% 
  dplyr::select(study_id, clinical.feat.list, -contains("SOFA")) %>% 
  pivot_longer(cols= -study_id) %>% 
  inner_join(patient_clust) %>% 
  na.omit() %>% 
  group_by(name, severity_lab) %>% 
  mutate(n_group= as.character(n()),
                  label_group= factor(paste0('n = ', n_group))) %>% 
    ungroup() %>% 
  group_by(name) %>% 
   mutate(label_pos = min(value),
          subcat = case_when(name %in% c("bili_max", "p_alat","p_asat") ~ "Liver function",
                             name %in% c("hb_min","wbc_count", "plt_count") ~ "Blood cells",
                             name %in% c("resp_rate_max","sat","syst_bp_min") ~ "Circulation",
                             .default=NA)) %>% 
   ungroup() %>% 
  mutate(name = factor(name, levels = c("crp_max","crea_max","inf_rbc_max",
                                         "hb_min","wbc_count","plt_count_min",
                                         "bili_max","p_asat","p_alat",
                                         "resp_rate_max","sat","syst_bp_min"
                                         ))) 

single_facet_fun = function(data)( 
  data %>% 
    ggplot(aes(x=severity_lab, y=value, fill= severity_lab)) +
    geom_violin(trim=F, show.legend = F, width=.6,lwd=.25) +
    geom_jitter(size=0.05,width = .1, show.legend = F) +
    geom_boxplot(aes(fill=severity_lab),alpha=.7, outlier.shape = NA,width=.2, show.legend = F,lwd=.25) +
    theme_bw(base_size = 6) +
    scale_y_continuous(expand=c(.2,0))+
    facet_grid(~label_name) +
    theme(axis.title.x = element_blank()) +
    scale_fill_manual(values=patient_kclust3_lab) +
    stat_compare_means(method = "wilcox.test",
                       label.sep = "\n",
                       hide.ns = T,
                       label = "p.signif", 
                       vjust = 0.5,
                       size=2,
                       comparisons = my_comparisons_severe) +
    labs(fill=NULL,
         x=NULL) +
    scale_x_discrete(labels=data$label_group))


## 
p_list <- df %>% 
  mutate(name = factor(name, levels = c("crp_max","crea_max","inf_rbc_max",
                                         "hb_min","wbc_count","plt_count_min",
                                         "bili_max","p_asat","p_alat",
                                         "resp_rate_max","sat","syst_bp_min"
                                         )),
         label_name = case_when(name == "bili_max" ~ "Bilirubin\n(\U003BCmol/L)",
                                name == "crea_max" ~ "Creatinine\n(\U003BCmol/L)",
                                name == "crp_max" ~ "CRP\n(mg/L)",
                                name == "hb_min" ~ "Hemoglobin\n(g/L)",
                                name == "inf_rbc_max" ~ "Parasitemia\n(%)",
                                name == "plt_count_min" ~ "Platelet\n(counts)",
                                name == "sat" ~ "Saturation\n(%)",
                                name == "p_asat" ~ "AST\n(U/L)",
                                name == "p_alat" ~ "ALT\n(U/L)",
                                name == "resp_rate_max" ~ "Respirations rate\n(bpm)",
                                name == "wbc_count" ~ "White blood cells\n(counts)",
                                name == "syst_bp_min" ~ "Systolic blood\npressure (mmHg)"
               ),
         label_unit = case_when(name == "bili_max" ~ "unit",
                                name == "crea_max" ~ "unit",
                                name == "crp_max" ~ "mg/L",
                                name == "hb_min" ~ "g/dL",
                                name == "inf_rbc_max" ~ "%",
                                name == "plt_count_min" ~ "counts",
                                name == "sat" ~ "%",
                                name == "p_asat" ~ "unit",
                                name == "p_alat" ~ "unit",
                                name == "resp_rate_max" ~ "bpm",
                                name == "wbc_count" ~ "counts",
                                name == "syst_bp_min" ~ "mmHg"
               )) %>% 
  arrange(name) %>% 
  group_by(name) %>% 
  nest() %>% 
  mutate(single_plot = purrr::map(data, single_facet_fun))
         

clin.data.severity.groups.new <- wrap_plots(p_list$single_plot, ncol=3)

clin.data.severity.groups.new.data <- p_list %>%
  unnest(data) %>% 
  compare_means(
    value ~ severity_lab, data = ., group.by = "name",
    method = "wilcox.test") %>% 
  transmute(name, group1, group2, p, p.adj, p.signif, method) 

## show plot
clin.data.severity.groups.new

Figure 4D

## nest data
#data_nested <- data.long %>% 
#  inner_join(sampleTable_simple, by="sample_id") %>% 
#  left_join(subjectTable %>% transmute(study_id, 
#                                       exposure = factor(endemic, levels=c("primary_infected","previously_exposed"))),
#            by="study_id") %>% 
#  group_by(UniProt,Assay) %>% 
#  nest()

#lme_res <- data_nested %>% 
#  mutate(lme.res = purrr::map(data, ~ lmer(NPX ~ Time * exposure + (1|study_id), REML = F,
#                                           data = .x %>% dplyr::filter(Time!="D10"))),
#         lme.tidy = purrr::map(lme.res, ~ broom.mixed::tidy(.)),
#         posthoc.time = purrr::map(lme.res, ~ summary(contrast(emmeans(., ~ Time), method = "pairwise")) %>% tibble()),
#         posthoc.time_exposure = purrr::map(lme.res, ~ summary(contrast(emmeans(., ~ Time * exposure), method = "pairwise")) %>% tibble())
#         )

######
data_nested.patclust <- data.long %>% 
  inner_join(sampleTable_simple, by="sample_id") %>% 
  inner_join(patient_clust,by="study_id") %>% 
  mutate(all_vs_1 = ifelse(cluster.orig %in% c("2","3"),"rest",
                           ifelse(cluster.orig =="1","1",NA)),
         all_vs_2 = ifelse(cluster.orig %in% c("1","3"),"rest",
                           ifelse(cluster.orig =="2","2",NA)),
         all_vs_3 = ifelse(cluster.orig %in% c("2","1"),"rest",
                           ifelse(cluster.orig =="3","3",NA))) %>% 
  group_by(UniProt,Assay) %>% 
  nest()

g_vs_conv <- data_nested.patclust %>%
   mutate(lme.res = purrr::map(data, ~ lmer(NPX ~ Time * severity_lab + (1|study_id), REML = F,
                                           data = .x %>% dplyr::filter(Time!="D10"))),
         lme.tidy = purrr::map(lme.res, ~ broom.mixed::tidy(.)),
         #posthoc.time = purrr::map(lme.res, ~ summary(contrast(emmeans(., ~ Time), method = "pairwise")) %>% tibble()),
         posthoc.time_exposure = purrr::map(lme.res, ~ summary(contrast(emmeans(., ~ Time * severity_lab), method = "pairwise")) %>% tibble())
         )

g_vs_conv_padj <- g_vs_conv %>% 
  unnest(cols="posthoc.time_exposure") %>% 
  #filter(contrast=="Acute severe - M12 severe") %>% 
  filter(contrast %in%c("Acute severe - M12 severe",
                        "Acute moderate - M12 moderate",
                        "Acute mild - M12 mild")) %>% 
      transmute(Assay, UniProt, contrast, estimate,SE,df,t.ratio,p.value) %>% 
  #filter(contrast=="Acute primary_infected - Acute previously_exposed") %>% 
  ungroup() %>% 
    group_by(contrast) %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
                  FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
    ungroup() %>% 
  arrange(p.adj)



(severity_groups_conv_volc <- g_vs_conv_padj %>% 
  group_by(contrast) %>% 
  mutate(severity_lab = case_when(grepl("severe",contrast) ~ "severe",
                                    grepl("moderate",contrast) ~ "moderate",
                                    grepl("mild",contrast) ~ "mild",
                                    .default = NA),
         severity_lab = factor(severity_lab, levels=c("severe","moderate","mild")),
         sig_col = case_when(FDR==T ~ severity_lab,
                             .default = NA)) %>% 
  #slice_max(order_by = estimate, n=1) %>% 
    ggplot(aes(x=severity_lab, y= estimate, color=sig_col)) +
    geom_jitter(width=.1,alpha=.2, show.legend = F,size=.5, shape=16) +
    ggrepel::geom_text_repel(data= . %>% 
                               group_by(severity_lab) %>% slice_max(n=8,order_by = estimate), aes(label=Assay), show.legend = F,force = .5,
                             segment.size=0.2,
                            segment.alpha=.1,
                            size=1.5,max.overlaps = 15, color="gray35") +
    ggrepel::geom_text_repel(data= . %>% 
                               group_by(severity_lab) %>% slice_min(n=8,order_by = estimate), aes(label=Assay), show.legend = F,force = .5,
                             segment.size=0.2,
                            segment.alpha=.1,
                            size=1.5, max.overlaps = 15, color="gray35") +
    geom_hline(yintercept=0, 
               linetype = 3) +
    scale_color_manual(values = patient_kclust3_lab,na.value = "grey") +
    labs(x=NULL,
         title="Each group vs convalecence",
         subtitle = "mixed effect model approach - acute_severity vs m12_severity",
         caption="FDR < 0.01"))

Figure 4E

require(UpSetR) # https://cran.r-project.org/web/packages/UpSetR/vignettes/basic.usage.html

g_vs_conv_padj_tmp.list <- g_vs_conv_padj %>% 
  group_by(contrast) %>% 
  mutate(severity_lab = case_when(grepl("severe",contrast) ~ "severe",
                                    grepl("moderate",contrast) ~ "moderate",
                                    grepl("mild",contrast) ~ "mild",
                                    .default = NA),
         severity_lab = factor(severity_lab, levels=c("severe","moderate","mild")),
         sig_col = case_when(FDR==T ~ severity_lab,
                             .default = NA)) %>%
    filter(estimate>1) %>% 
  group_by(severity_lab) %>%
  summarise(list = list(Assay)) %>%
  mutate(list = setNames(list, severity_lab)) %>%
  pull(list)

severe_log1 <- intersect(setdiff(g_vs_conv_padj_tmp.list$severe, g_vs_conv_padj_tmp.list$mild),
                         setdiff(g_vs_conv_padj_tmp.list$severe, g_vs_conv_padj_tmp.list$moderate))

pdf(paste0(result.tmp.dir,"severity_daps_upset.pdf"),width = 7, height = 3) 
(UpSetR::upset(fromList(g_vs_conv_padj_tmp.list),
              order.by = "freq",point.size = 2,
              text.scale = 1.2,
             #mb.ratio = c(0.6, 0.4),
              sets.bar.color = c("severe" = "#ca0020","moderate" = "#f4a582", "mild" = "#92c5de"),
              keep.order = TRUE,
              mainbar.y.label = "Number of Proteins", 
              sets.x.label = "Proteins per group"))
dev.off()
## quartz_off_screen 
##                 2

Supplementary Table S3

library(gtsummary)
(severityTable <- subjectTable %>% 
  mutate(wbc_count = as.numeric(wbc_count),
         sat = as.numeric(sat)) %>% 
  left_join(patient_clust, by="study_id") %>% 
    tbl_summary(include = c(inf_rbc_max,
                            crp_max,
                            bili_max,
                            crea_max,
                            sat,
                            resp_rate_max,
                            syst_bp_min,
                            plt_count_min,
                            hb_min),
              by = severity_lab, # split table by group
              statistic = list(
                all_continuous() ~ "{median} ({min}-{max})",
                all_categorical() ~ "{n} / {N} ({p}%)"
              ),
              digits = all_continuous() ~ 2,
              missing_text = "(Missing)") %>% 
  add_n() %>% # add column with total number of non-missing observations
  add_p() %>% # test for a difference between groups
  modify_header(label = "**Variable**") %>% # update the column header
  bold_labels())
Variable N severe, N = 231 moderate, N = 331 mild, N = 161 p-value2
inf_rbc_max 72 1.20 (0.01-8.00) 0.90 (0.10-5.00) 0.25 (0.01-1.80) 0.042
crp_max 72 208.00 (88.00-381.00) 143.00 (28.00-266.00) 91.50 (14.00-246.00) <0.001
bili_max 64 25.00 (12.00-135.00) 19.00 (10.00-100.00) 19.00 (5.00-173.00) 0.093
    (Missing) 0 4 4
crea_max 72 106.00 (68.00-828.00) 94.00 (47.00-142.00) 84.00 (49.00-122.00) 0.2
sat 72 >0.9
    92 0 / 23 (0%) 1 / 33 (3.0%) 1 / 16 (6.3%)
    93 1 / 23 (4.3%) 1 / 33 (3.0%) 0 / 16 (0%)
    94 0 / 23 (0%) 1 / 33 (3.0%) 0 / 16 (0%)
    95 2 / 23 (8.7%) 4 / 33 (12%) 2 / 16 (13%)
    96 2 / 23 (8.7%) 3 / 33 (9.1%) 0 / 16 (0%)
    97 4 / 23 (17%) 3 / 33 (9.1%) 4 / 16 (25%)
    98 8 / 23 (35%) 9 / 33 (27%) 5 / 16 (31%)
    99 4 / 23 (17%) 5 / 33 (15%) 3 / 16 (19%)
    100 2 / 23 (8.7%) 6 / 33 (18%) 1 / 16 (6.3%)
resp_rate_max 72 20.00 (14.00-48.00) 20.00 (12.00-42.00) 16.00 (13.00-32.00) 0.058
syst_bp_min 72 100.00 (70.00-130.00) 108.00 (76.00-139.00) 108.00 (90.00-125.00) 0.2
plt_count_min 71 38.00 (14.00-112.00) 72.50 (28.00-134.00) 104.00 (51.00-183.00) <0.001
    (Missing) 0 1 0
hb_min 72 115.00 (64.00-157.00) 119.00 (66.00-165.00) 114.00 (66.00-159.00) 0.8
1 Median (Minimum-Maximum); n / N (%)
2 Kruskal-Wallis rank sum test; Fisher’s exact test
subjectTable %>% 
  mutate(wbc_count = as.numeric(wbc_count),
         sat = as.numeric(sat)) %>% 
  left_join(patient_clust, by="study_id") %>% 
  transmute(study_id, 
            severity_lab,
            diff_acuteSample_treatment,diff_acuteSample_treatment.abs,
            diff_acuteSample_spt_current,diff_acuteSample_spt_current.abs) %>% 
  pivot_longer(cols = -c(study_id,severity_lab)) %>% 

compare_means(
    value ~ severity_lab, data = ., group.by = "name",
    method = "wilcox.test")
## # A tibble: 12 × 9
##    name                 .y.   group1 group2     p p.adj p.format p.signif method
##    <chr>                <chr> <chr>  <chr>  <dbl> <dbl> <chr>    <chr>    <chr> 
##  1 diff_acuteSample_tr… value severe moder… 0.875     1 0.88     ns       Wilco…
##  2 diff_acuteSample_tr… value severe mild   0.286     1 0.29     ns       Wilco…
##  3 diff_acuteSample_tr… value moder… mild   0.244     1 0.24     ns       Wilco…
##  4 diff_acuteSample_tr… value severe moder… 0.933     1 0.93     ns       Wilco…
##  5 diff_acuteSample_tr… value severe mild   0.286     1 0.29     ns       Wilco…
##  6 diff_acuteSample_tr… value moder… mild   0.322     1 0.32     ns       Wilco…
##  7 diff_acuteSample_sp… value severe moder… 0.626     1 0.63     ns       Wilco…
##  8 diff_acuteSample_sp… value severe mild   0.755     1 0.76     ns       Wilco…
##  9 diff_acuteSample_sp… value moder… mild   0.379     1 0.38     ns       Wilco…
## 10 diff_acuteSample_sp… value severe moder… 0.626     1 0.63     ns       Wilco…
## 11 diff_acuteSample_sp… value severe mild   0.755     1 0.76     ns       Wilco…
## 12 diff_acuteSample_sp… value moder… mild   0.379     1 0.38     ns       Wilco…

Supplemementary Table S4

#clin.data.severity.groups.new.data %>%
 # write_tsv(paste0(result.dir,"Supplementary_TableS4_ClinicalChemistry_severity_groups.tsv"))

clin.data.severity.groups.new.data %>% head()
## # A tibble: 6 × 7
##   name     group1   group2          p p.adj p.signif method  
##   <fct>    <chr>    <chr>       <dbl> <dbl> <chr>    <chr>   
## 1 crp_max  severe   moderate 0.00237  0.076 **       Wilcoxon
## 2 crp_max  severe   mild     0.000495 0.017 ***      Wilcoxon
## 3 crp_max  moderate mild     0.0963   1     ns       Wilcoxon
## 4 crea_max severe   moderate 0.177    1     ns       Wilcoxon
## 5 crea_max severe   mild     0.0863   1     ns       Wilcoxon
## 6 crea_max moderate mild     0.550    1     ns       Wilcoxon

Figure S8A

prot.input <- prot.data.4.corr %>% column_to_rownames("study_id")
clin.input <- clin.data.4.corr %>% dplyr::select(study_id,c(plt_count_min,inf_rbc_max,crp_max,hb_min,bili_max,crea_max,p_alat,p_asat)) %>% #,contains("SOFA")) %>%
  column_to_rownames("study_id")

cor.res <- prot.input[rownames(clin.input),] %>% 
  correlation::correlation(data2 = clin.input,
                           method = "spearman", 
                           redundant = F, 
                           p_adjust = "fdr") %>% 
  tibble()
df <- cor.res %>%
  filter(n_Obs >= 37, 
         p<=0.05,
         abs(rho)>=0.45
         ) %>% 
  transmute(from=Parameter2, 
            to=Parameter1,
            value=rho) %>% 
  group_by(to) %>% 
  mutate(n_prot =n()) %>% 
  ungroup() %>% 
  group_by(from) %>% 
  mutate(n_clin = n()) %>% 
  ungroup() %>% 
  arrange(desc(n_prot),n_clin) %>% 
   mutate(from = case_when(from=="crp_max"~"CRP",
                          from=="p_alat"~"ALT",
                          from=="p_asat"~"AST",
                          from=="plt_count_min"~"Platelets",
                          from=="inf_rbc_max" ~"Parasitemia",
                          from=="bili_max"~"Bilirubin",
                          from=="hb_min" ~"Hemoglobin",
                          from=="crea_max"~"Creatinine",
                          .default=from)) 
  
df
## # A tibble: 163 × 5
##    from  to    value n_prot n_clin
##    <chr> <chr> <dbl>  <int>  <int>
##  1 CRP   CTSL  0.471      3     22
##  2 CRP   ICAM1 0.489      3     22
##  3 CRP   KYNU  0.467      3     22
##  4 CRP   PTS   0.462      3     22
##  5 CRP   PVR   0.450      3     22
##  6 ALT   CTSL  0.463      3     33
##  7 ALT   ICAM1 0.557      3     33
##  8 ALT   KYNU  0.467      3     33
##  9 ALT   PTS   0.525      3     33
## 10 ALT   PVR   0.528      3     33
## # ℹ 153 more rows
#string <- unique(df$from) 
#string <- setdiff(unique(df$from),names(clin_marker_cols))
#col.grid_clin <- setNames(sample(brewer.pal(length(string),name="Set1")),string)

string_proteins <- unique(df$to)
col.grid.prot <- setNames(rep("grey80",length(string_proteins)), string_proteins)



col.grid <- c(clin_marker_cols,
              #col.grid_clin, 
              col.grid.prot)

## highlight
# three-column data frame in which the first two columns correspond to row names and column names in the matrix, and the third column corresponds to the graphic parameters
border_df = data.frame(c("Parasitemia"), c("CALCA"), c(1))


pdf(paste0(result.tmp.dir,"chordDiagram.pdf")) #width 6.9

circos.par(gap.after = c(rep(1, length(unique(df[[1]]))-1), 15, 
                         rep(1, length(unique(df[[2]]))-1), 15))
chordDiagram(df,
            #  big.gap = 25,
             grid.col = col.grid,
             #annotationTrack = "grid",
                        big.gap = 10,
            small.gap = 1,
link.border = border_df,
             annotationTrack = NULL,
             preAllocateTracks = list(track.height = .1))#max(strwidth(unlist(dimnames(df))))))
circos.track(track.index = 1, panel.fun = function(x, y) {
  circos.text(CELL_META$xcenter, 
              CELL_META$ylim[1],
              CELL_META$sector.index,
              facing = "clockwise",
              cex = 0.6,
              niceFacing = TRUE, 
              adj = c(0, 0.9))
},
bg.border = NA)

#
dev.off()
## quartz_off_screen 
##                 2
circos.clear()

Figure 5

Identification of severity-associated plasma proteomic profiles

## WGCNA
## https://bioinformaticsworkbook.org/tutorials/wgcna.html#gsc.tab=0
#install.packages("BiocManager")
#BiocManager::install("WGCNA")

## data wrangling
selected.assays.wcna <- dap.res %>% filter(p.adj <= 0.01) %>% pull(Assay)

## requires: rows = treatments and columns = gene probes
input_mat <- data.wide %>% 
  inner_join(sampleTable_simple %>% dplyr::select(DAid,study_id,Time, sample_id),by="sample_id") %>% 
  inner_join(subjectTable %>% dplyr::select(study_id),by="study_id") %>% 
  filter(Time=="Acute") %>% 
  column_to_rownames("sample_id") %>% 
  ## restricting to proteins, significant abundant over convalescence (m12 samples)
  dplyr::select(selected.assays.wcna) %>% 
  as.matrix() %>%
  scale()

input_mat[1:5,1:10]
##                   TNFRSF8       IL10      CXCL9        CD74   TNFRSF1B
## 2011PT01|Acute -0.7370011 -1.1852994 -1.4157459  0.08771475 -1.9048313
## 2011PT04|Acute -0.6779312  0.3667134 -0.0943544 -0.19212623  0.2678492
## 2011PT05|Acute  0.1403045  1.0528265  0.5657621  1.29297919  0.3504350
## 2011PT06|Acute  0.2332304 -1.7527932 -1.0945056 -0.41377242 -0.4221094
## 2011PT07|Acute  0.9822293  1.4187290  0.7498430  1.43859264  1.2466066
##                     VCAM1     PLA2G2A     IL18BP       CSF1     B4GALT1
## 2011PT01|Acute -1.1412591 -1.01940457 -1.4608293 -1.6021606 -0.54555371
## 2011PT04|Acute -0.3286294  0.09020523 -0.5969576 -0.3028854 -0.45244260
## 2011PT05|Acute  0.4595043  0.74644622  0.5612046  0.1410837  1.00463269
## 2011PT06|Acute -0.2196398  0.29812935 -0.9891447 -0.5298451  0.04218177
## 2011PT07|Acute  0.9852817  1.00324357  1.1329858  1.2435433  1.42461678
dim(input_mat)
## [1]  72 692

Set up

allowWGCNAThreads()          # allow multi-threading (optional)
## Allowing multi-threading with up to 10 threads.
#> Allowing multi-threading with up to 4 threads.

# Choose a set of soft-thresholding powers
powers = c(c(1:10), seq(from = 12, to = 20, by = 2))

# Call the network topology analysis function
sft = pickSoftThreshold(input_mat,             # <= Input data
                        #blockSize = 30,
                        powerVector = powers,
                        verbose = 5
)
## pickSoftThreshold: will use block size 692.
##  pickSoftThreshold: calculating connectivity for given powers...
##    ..working on genes 1 through 692 of 692
##    Power SFT.R.sq  slope truncated.R.sq  mean.k. median.k. max.k.
## 1      1   0.0296 -0.367          0.729 159.0000  1.58e+02 283.00
## 2      2   0.4780 -1.210          0.871  57.1000  5.25e+01 154.00
## 3      3   0.6850 -1.480          0.924  25.5000  2.07e+01  94.80
## 4      4   0.7540 -1.640          0.955  13.0000  9.36e+00  62.40
## 5      5   0.7920 -1.700          0.970   7.2400  4.50e+00  42.90
## 6      6   0.8230 -1.730          0.960   4.3100  2.34e+00  30.60
## 7      7   0.8240 -1.780          0.920   2.6900  1.27e+00  22.40
## 8      8   0.8640 -1.770          0.973   1.7600  7.56e-01  16.80
## 9      9   0.8850 -1.780          0.962   1.1800  4.33e-01  12.80
## 10    10   0.8950 -1.760          0.951   0.8200  2.78e-01   9.90
## 11    12   0.2970 -2.640          0.140   0.4230  1.07e-01   6.19
## 12    14   0.3330 -3.490          0.324   0.2360  4.37e-02   4.03
## 13    16   0.3400 -3.470          0.314   0.1400  1.93e-02   2.72
## 14    18   0.3360 -3.350          0.298   0.0883  8.49e-03   1.91
## 15    20   0.3310 -3.240          0.306   0.0582  4.06e-03   1.43
#sft$powerEstimate

#### Scale independence & mean connectivity

sft_tibble <- as_tibble(sft$fitIndices)

plot.si <- sft_tibble %>% 
  ggplot(aes(x=Power,
             y=-sign(slope)*SFT.R.sq)) +
  geom_point() +
  geom_label(aes(label=Power)) +
  geom_hline(yintercept = 0.9, color="darkred") +
  theme_minimal() +
  labs(title = "Scale independence",
       y="Scale Free Topology Model fit\n signed R^2",
       x= "Soft Threshold (power")

plot.meank <- sft_tibble %>% 
  ggplot(aes(x=Power,
             y=mean.k.)) +
    geom_label(aes(label=Power)) +
    theme_minimal() +
  labs(title="Mean connectivity",
       x="Soft Threshold (power)",
       y="Mean Connectivity")

plot.si + plot.meank

##Build co-expression network

picked_power = 6#sft$powerEstimate#6
temp_cor <- cor       
cor <- WGCNA::cor         # Force it to use WGCNA cor function (fix a namespace conflict issue)
netwk <- blockwiseModules(input_mat,  # <= input here
                          # == Adjacency Function ==
                          power = picked_power,  # <= power here
                          networkType = "signed",#"signed hybrid",#"signed",
                          # == Tree and Block Options ==
                          deepSplit = 4, #sensitive module detection should be to module splitting, 0 least and 4 most sensitive
                          pamRespectsDendro = F,
                          # detectCutHeight = 0.75,
                          minModuleSize = 30, 
                          maxBlockSize =ncol(input_mat),#4000, 
                          # == Module Adjustments ==
                          reassignThreshold = 0,
                          mergeCutHeight = 0.25,
                          # == TOM == Archive the run results in TOM file (saves time)
                          saveTOMs = T,
                          saveTOMFileBase = "ER",
                          # == Output Options
                          numericLabels = T,
                          verbose = 3)
##  Calculating module eigengenes block-wise from all genes
##    Flagging genes and samples with too many missing values...
##     ..step 1
##  ..Working on block 1 .
##     TOM calculation: adjacency..
##     ..will use 10 parallel threads.
##      Fraction of slow calculations: 0.000000
##     ..connectivity..
##     ..matrix multiplication (system BLAS)..
##     ..normalization..
##     ..done.
##    ..saving TOM for block 1 into file ER-block.1.RData
##  ....clustering..
##  ....detecting modules..
##  ....calculating module eigengenes..
##  ....checking kME in modules..
##      ..removing 84 genes from module 1 because their KME is too low.
##      ..removing 5 genes from module 2 because their KME is too low.
##      ..removing 11 genes from module 3 because their KME is too low.
##      ..removing 1 genes from module 4 because their KME is too low.
##  ..merging modules that are too close..
##      mergeCloseModules: Merging modules whose distance is less than 0.25
##        Calculating new MEs...
cor <- temp_cor     # Return cor function to original namespace
##### Cluster Dendrogram
# Convert labels to colors for plotting
mergedColors = labels2colors(netwk$colors)
# Plot the dendrogram and the module colors underneath
(cluster_dendro <- plotDendroAndColors(
  netwk$dendrograms[[1]],
  mergedColors[netwk$blockGenes[[1]]],
  "Module colors",
  dendroLabels = FALSE,
  hang = 0.03,
  addGuide = TRUE,
  guideHang = 0.05 ))

## $mar
## [1] 1 5 0 1
module_df <- data.frame(
  assay_id = names(netwk$colors),
  Assay = gsub("\\_.*","",names(netwk$colors)),
  colors = labels2colors(netwk$colors)
)

module_df[1:5,]
##   assay_id    Assay    colors
## 1  TNFRSF8  TNFRSF8 turquoise
## 2     IL10     IL10     brown
## 3    CXCL9    CXCL9     brown
## 4     CD74     CD74     brown
## 5 TNFRSF1B TNFRSF1B turquoise
tmp <- unique(module_df$colors)
module.cols <- setNames(tmp, tmp)

Supplementary Figure 9

Figure S9A

## how many proteis in each module
(module_overview <- module_df %>% 
  group_by(colors) %>% 
  count() %>% 
  
  ggplot(aes(x = fct_reorder(colors,-n), y = n, fill = colors, label = n)) +
         geom_bar(stat = "summary", position = "dodge", show.legend = F) +
  geom_text(stat = "sum", vjust = -0.5,show.legend = F, size=2) +
  scale_y_continuous(#limits=c(0,300),
                     expand = c(0, 20)) +
   scale_x_discrete(expand = c(0,-1)) +
  scale_fill_manual(values=module.cols) +
  theme_minimal() +
  theme(axis.text.x = element_blank(),
    axis.text = element_text(size=6), 
    axis.title = element_text(size=6), 
    axis.ticks.x = element_blank()
    ) + 
  labs(title = "WGCNA analysis - protein network modules",
       subtitle = paste0("based on ",dim(input_mat)[2]," proteins (differential abundant proteins)\n",
                         "profiled in ",dim(input_mat)[1]," acute malaria samples"),
       x="WGCNA protein modules",
       y="n Proteins") 
)

#### generate and export networks for all modules

assays_of_interest = module_df #%>%
  #subset(colors %in% c("turquoise"))

npx_of_interest = input_mat[,assays_of_interest$assay_id]
npx_of_interest[1:5,1:5]
##                   TNFRSF8       IL10      CXCL9        CD74   TNFRSF1B
## 2011PT01|Acute -0.7370011 -1.1852994 -1.4157459  0.08771475 -1.9048313
## 2011PT04|Acute -0.6779312  0.3667134 -0.0943544 -0.19212623  0.2678492
## 2011PT05|Acute  0.1403045  1.0528265  0.5657621  1.29297919  0.3504350
## 2011PT06|Acute  0.2332304 -1.7527932 -1.0945056 -0.41377242 -0.4221094
## 2011PT07|Acute  0.9822293  1.4187290  0.7498430  1.43859264  1.2466066
## columns: Assays
## rows: sample_id

TOM = TOMsimilarityFromExpr(npx_of_interest,
                            power = picked_power)
## TOM calculation: adjacency..
## ..will use 10 parallel threads.
##  Fraction of slow calculations: 0.000000
## ..connectivity..
## ..matrix multiplication (system BLAS)..
## ..normalization..
## ..done.
# Add gene names to row and columns
row.names(TOM) = colnames(npx_of_interest)
colnames(TOM) = colnames(npx_of_interest)

edge_list = data.frame(TOM) %>%
  rownames_to_column("Assay1") %>% 
  pivot_longer(cols=-Assay1,names_to = "Assay2",values_to = "adjacency") %>% 
  distinct() %>%
    filter(Assay1!=Assay2) %>% 
  right_join(module_df %>% transmute(module1 = colors,
                                     Assay1 = Assay)) %>% 
  right_join(module_df %>% transmute(module2 = colors,
                                     Assay2 = Assay)) %>% 
  na.omit()

Figure 5A

##Heatmap - protein adjacency

mat <- cor(npx_of_interest, method = "pearson")
row.anno.df <- data.frame(assay_id = rownames(mat)) %>% left_join(module_df) %>% dplyr::rename(Module = colors) 

(assay_adj_hm <- mat %>% 
  Heatmap(name="protein-protein correlation r",
          right_annotation = HeatmapAnnotation(df = row.anno.df %>% transmute(Module),
                                               col = list(Module = module.cols), 
                                               which = "row",
                                               simple_anno_size = unit(1, "mm"),
                                               show_annotation_name = F,
                                               annotation_name_rot = 0,
                                               annotation_name_gp = gpar(fontsize=6),

                                               annotation_name_side = "top",
                                               show_legend = F,
                                               annotation_legend_param = list(title_gp = gpar(fontsize = 6), 
                                                                              labels_gp = gpar(fontsize = 6))),
          row_split = row.anno.df$Module,
          column_split = row.anno.df$Module,
          row_gap = unit(0, "mm"),
          column_gap = unit(0, "mm"), 
          row_dend_width = unit(3, "mm"),
          row_dend_gp = gpar(lwd=.1),
          column_dend_gp = gpar(lwd=.1),
          column_dend_height = unit(3, "mm"), 
          border = TRUE,
          border_gp = gpar(lwd=.1),
          column_title = NULL,
          row_title = NULL,
          show_row_names = F,
          show_column_names = F,
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                      title_gp = gpar(fontsize = 6),
                                      direction = "horizontal",
                                      legend_width = unit(2, "cm"),
                                      grid_height = unit(.2, "cm"))
          ))

# Get Module Eigengenes per cluster
MEs0 <- moduleEigengenes(input_mat, mergedColors)$eigengenes

# Reorder modules so similar modules are next to each other
MEs0 <- orderMEs(MEs0)
module_order = names(MEs0) %>% gsub("ME","", .)

# Add treatment names
#MEs0$DAid <- row.names(MEs0)

# tidy data
mME <- MEs0 %>%
  rownames_to_column("sample_id") %>% 
  pivot_longer(names_to = "module", values_to = "module_eigengenes" ,cols = -sample_id) %>%
      separate(sample_id, "\\|", into = c("study_id","Time"),remove = F) %>% 
  mutate(module = gsub("ME", "", module),
         module = factor(module, levels = module_order)) %>% 
  inner_join(subjectTable, 
             by="study_id") 

Figure 5B

## Module-trait relationship

corr_module_eigengene_meta_res <- mME %>% 
  dplyr::select(module, module_eigengenes,contains("SOFA")) %>% 
  group_by(module) %>% 
  correlation(p_adjust = "fdr") 

df <- tibble(corr_module_eigengene_meta_res) %>% 
  filter(Parameter1=="module_eigengenes") %>% 
    mutate(r4fill = case_when(p>0.05 ~ 0,
                              .default=r))  
(module_trait_plot <- ggplot(data = df, 
                             aes(x=Parameter2, y=Group, fill=r4fill,lable=r)) +
    geom_tile() +
    geom_text(aes(label = paste0(r %>% round(2)),
                  color = ifelse(r4fill==0, "grey20", "black")),
              size=1) +
    scale_colour_identity() +
    theme_bw() +
    scale_fill_gradient2(
      low = "blue",
      high = "red",
      mid = "white",
      midpoint = 0,
      limit = c(-1,1)) +
    labs(title = "Module-trait Relationships",
         y="WGCNA modules",
         x = NULL, 
         fill="rho") +
    theme(#axis.text.y = element_text(color= rev(c("yellow","turquoise","red","grey","green","brown","blue"))),
      axis.text.y = element_text(color= rev(c("yellow","turquoise","red","grey","green","brown","blue"))),
          axis.text.x = element_text(angle=45, hjust=1)))

#### Module membership

###  Get Module Eigengenes per cluster
MEs <- moduleEigengenes(input_mat, mergedColors)$eigengenes

## calculate Module membership
geneModuleMembership <- as.data.frame(cor(input_mat, MEs, use = "p")) 

geneModuleMembership.tidy <- geneModuleMembership %>%
  rownames_to_column("Assay") %>% 
  pivot_longer(cols = -Assay) %>% 
  transmute(Assay,
            Module = str_remove(name, "ME"),
            gMM = value)

## calculate pvalue for geneModuleMembership
MMPvalue.tidy <- as.data.frame(corPvalueStudent(as.matrix(geneModuleMembership), nrow(input_mat))) %>%
  rownames_to_column("Assay") %>% 
  pivot_longer(cols = -Assay) %>% 
  transmute(Assay,
            Module = str_remove(name, "ME"),
            pvalue = value) 

gMM.tidy <- geneModuleMembership.tidy %>% right_join(MMPvalue.tidy,by=c("Assay","Module")) 

module_specific_MM <- module_df %>% 
  transmute(Assay,
            Module = colors) %>% 
  inner_join(gMM.tidy)

Supplementary Figur S8B

(turquoise_module_restrictions_density <- module_specific_MM %>% 
   mutate("-log10(pvalue)" = -log10(pvalue)) %>% 
   pivot_longer(cols = c(gMM,"-log10(pvalue)")) %>% 
   mutate(name_label = case_when(name=="gMM"~"threshold > 0.6",
                                 name=="-log10(pvalue)"~"threshold < 0.05",
                                 .default = NA),
          name_label = factor(name_label),
          cutoff = case_when(name=="gMM"~ 0.6,#0.75,
                             name=="-log10(pvalue)"~ -log10(0.05),
                             .default = NA),
          cutoff_pos_y = case_when(name=="gMM"~ 1,
                                   name=="-log10(pvalue)"~ 0.04,
                                   .default = NA)
   ) %>% 
   ggplot(aes(x=value)) +
   geom_density(show.legend = F,linewidth=.2,fill="turquoise") +
   theme_minimal() +
   facet_wrap(~name, ncol = 1,labeller = labeller(name=c("gMM" = "Module membership", "-log10(pvalue)" = "-log10(pvalue)")),scales = "free") +
   geom_vline(aes(xintercept=cutoff),linetype="dashed") +
   geom_text(aes(x=cutoff,
                 y=cutoff_pos_y,
                 label=name_label), 
             size=1,
             check_overlap = TRUE) +
   labs(y="density",
        x=""))

Figure 5C

restricted_module_turquoise <- module_specific_MM %>% 
  filter(Module=="turquoise",
         gMM > 0.6,#0.75,
         pvalue < 0.05
         ) %>% 
  arrange(-pvalue) %>% 
  pull(Assay) 

length(restricted_module_turquoise)
## [1] 161
data.frame(Assay = restricted_module_turquoise) %>% 
  left_join(dap.res %>% 
              transmute(Assay, UniProt)) %>%
  transmute(UniProt) %>% 
  write_tsv(paste0(result.tmp.dir,"restricted_module_turquoise.tsv"))
  #head()
##Online reactome
reactome_result<- read_delim("../Manuscript/20250226_restricted_module_turquoise_ReactomeORA_Result.txt") %>% janitor::clean_names()


(reactome_ora <- reactome_result %>% 
  arrange(entities_fdr) %>% 
  head(n=10) %>% 
    mutate(facet_lab = "turquoise module") %>% 

   ggplot(aes(x=fct_reorder(pathway_name,-log10(entities_fdr)), 
              y=-log10(entities_fdr))) +

    geom_bar(stat = "identity", width = 0.1) +
    geom_point(aes(color=-log10(entities_fdr)),
               size=2) +
    geom_text(aes(label=number_entities_found),
              size=2, nudge_y = .1, color="black")+
    scale_y_continuous(trans="log10") +
    scale_x_discrete(labels = function(x) str_wrap(x, width = 45)) +
        scale_color_viridis() +
    theme_minimal() +
    theme(text = element_text(size=6 ),
          axis.text.y = element_text(size = 6),
          axis.ticks.x = element_blank()) +
    coord_flip() +
    facet_grid(~facet_lab) +
    guides(size = guide_legend(reverse=TRUE),
           ) +
     labs(title = "Reactome database v86",
       color="-log10\n(FDR)",
       y="-log10(FDR)",
       x=NULL)
)

Figure 5D

wrapper <- function(x, ...) 
{
  paste(strwrap(x, ...), collapse = "\n")
}

a = "Immunoregulatory interactions between a Lymphoid and a non-Lymphoid cell"
df <- reactome_result %>% 
  arrange(entities_fdr) %>% 
  head(n=10) %>% 
  filter(pathway_name==a) %>% 
  transmute(pathway_name, submitted_entities_found) %>% 
  separate_rows(submitted_entities_found, sep=";\\s*") %>% 
  left_join(
    data.long %>% inner_join(sampleTable_simple, by="sample_id") %>% transmute(Assay,NPX,UniProt,sample_id,study_id,Time) %>% filter(Time=="Acute"),
    by=c("submitted_entities_found"="UniProt")
  ) %>% 
  inner_join(patient_clust,by="study_id")

(reactome_ora_IIBLNL <- df %>%  group_by(Assay, severity_lab) %>% 
    summarise(NPXmean = mean(NPX),
              NPXmedian = median(NPX),
              NPXsd = sd(NPX),
              NPXn = n(),
              NPXse = NPXsd / sqrt(NPXn)
    ) %>% 
    mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
    ggplot(aes(x=Assay, y=NPXmean, group=severity_lab, color=severity_lab)) +
    geom_point(size=.25) +
    geom_polygon(fill=NA, show.legend = F, lwd=0.2) +
    geom_errorbar(aes(x = Assay,
                      ymin=NPXmean-NPXci95, 
                      ymax=NPXmean+NPXci95, ),
                  linewidth=.5, 
                  width=.2,
                  alpha=.5) +
    # Make it circular!
    coord_polar(clip = "off") +
    theme_minimal() +
    labs(x="",
         y="mean (NPX) +- 95% CI",

         title = wrapper(a, width = 40),
                  color="mean (NPX) +- 95% CI") +
    scale_color_manual(values=patient_kclust3_lab) +
    # Annotate the bars and the lollipops so the reader understands the scaling
    annotate(x = 0, y = 0, label = "0", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 1, label = "1", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 2, label = "2", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 3, label = "3", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    theme(
      axis.title = element_blank(),
      axis.ticks = element_blank(),
      axis.text.y = element_blank(),
      axis.text.x = element_text(color = "gray12", size = 4),
      legend.position = "right",
      legend.text = element_text(size=6),
      legend.title = element_text(size=6),
      title = element_text(size=5, face='bold'),
      plot.title = element_text(hjust = 0.5))
  )

a = "Neutrophil degranulation"
df <- reactome_result %>% 
  arrange(entities_fdr) %>% 
  head(n=10) %>% 
  filter(pathway_name==a) %>% 
  transmute(pathway_name, submitted_entities_found) %>% 
  separate_rows(submitted_entities_found, sep=";\\s*") %>% 
  left_join(
    data.long %>% inner_join(sampleTable_simple, by="sample_id") %>% transmute(Assay,NPX,UniProt,sample_id,study_id,Time) %>% filter(Time=="Acute"),
    by=c("submitted_entities_found"="UniProt")
  ) %>% 
  inner_join(patient_clust,by="study_id")

(reactome_ora_ND <- df %>%  group_by(Assay, severity_lab) %>% 
    summarise(NPXmean = mean(NPX),
              NPXmedian = median(NPX),
              NPXsd = sd(NPX),
              NPXn = n(),
              NPXse = NPXsd / sqrt(NPXn)
    ) %>% 
    mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
    ggplot(aes(x=Assay, y=NPXmean, group=severity_lab, color=severity_lab)) +
    geom_point(size=.25) +
    geom_polygon(fill=NA, show.legend = F, lwd=0.2) +
    geom_errorbar(aes(x = Assay,
                      ymin=NPXmean-NPXci95, 
                      ymax=NPXmean+NPXci95, ),
                  linewidth=.5,    
                  width=.2,
                  alpha=.5) +
    # Make it circular!
    coord_polar(clip = "off") +
    theme_minimal() +
    labs(x="",
         title = wrapper(a, width = 40),
                  color="mean (NPX) +- 95% CI") +
    scale_color_manual(values=patient_kclust3_lab) +
    # Annotate the bars and the lollipops so the reader understands the scaling
    annotate(x = 0, y = 0, label = "0", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 1, label = "1", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 2, label = "2", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 3, label = "3", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    theme(
      axis.title = element_blank(),
      axis.ticks = element_blank(),
      axis.text.y = element_blank(),
      axis.text.x = element_text(color = "gray12", size = 4),
      legend.position = "right",
      legend.text = element_text(size=6),
      legend.title = element_text(size=6),
      title = element_text(size=5, face='bold'),
      plot.title = element_text(hjust = 0.5))
  )

a = "TNFR2 non-canonical NF-kB pathway"
df <- reactome_result %>% 
  arrange(entities_fdr) %>% 
  head(n=10) %>% 
  filter(pathway_name==a) %>% 
  transmute(pathway_name, submitted_entities_found) %>% 
  separate_rows(submitted_entities_found, sep=";\\s*") %>% 
  left_join(
    data.long %>% inner_join(sampleTable_simple, by="sample_id") %>% transmute(Assay,NPX,UniProt,sample_id,study_id,Time) %>% filter(Time=="Acute"),
    by=c("submitted_entities_found"="UniProt")
  ) %>% 
  inner_join(patient_clust,by="study_id")

(reactome_ora_TNFR2 <- df %>%  group_by(Assay, severity_lab) %>% 
    summarise(NPXmean = mean(NPX),
              NPXmedian = median(NPX),
              NPXsd = sd(NPX),
              NPXn = n(),
              NPXse = NPXsd / sqrt(NPXn)
    ) %>% 
    mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
    ggplot(aes(x=Assay, y=NPXmean, group=severity_lab, color=severity_lab)) +
    geom_point(size=.25) +
    geom_polygon(fill=NA, show.legend = F, lwd=0.2) +
    geom_errorbar(aes(x = Assay,
                      ymin=NPXmean-NPXci95, 
                      ymax=NPXmean+NPXci95),
                  linewidth=.5,
                  width=.2,
                  alpha=.5) +
    # Make it circular!
    coord_polar(clip = "off") +
    theme_minimal() +
    labs(x=NULL,
         color="mean (NPX) +- 95% CI",
         title = wrapper(a, width = 40)) +
    scale_color_manual(values=patient_kclust3_lab) +
    # Annotate the bars and the lollipops so the reader understands the scaling
    annotate(x = 0, y = 0, label = "0", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 1, label = "1", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 2, label = "2", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 3, label = "3", fontface =2, geom = "text", color = "gray12", size = 1.5) +
  annotate(x = 0, y = 4, label = "4", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    theme(
      axis.ticks = element_blank(),
      axis.title = element_blank(),
      axis.text.y = element_blank(),
      axis.text.x = element_text(color = "gray12", size = 4),
      legend.position = "right",
      legend.text = element_text(size=6),
      legend.title = element_text(size=6),
      title = element_text(size=5, face='bold'),
      plot.title = element_text(hjust = 0.5))
)

Figure 6

Severity-associated profiles of condensed 11- protein signature in malaria and other febrile infections.

library(mixOmics)
data.mo <- df_acute_patclust_incl_conv %>% 
  filter(Assay %in% restricted_module_turquoise) %>% 
  pivot_wider(names_from = Assay, values_from = NPX, id_cols=c(severity_lab,sample_id)) %>% 
  column_to_rownames("sample_id")

X <- data.mo %>% dplyr::select(-c(severity_lab))
Y <- data.mo$severity_lab
#####
data.pca <- mixOmics::pca(X, ncomp=10, center = TRUE, scale = TRUE)
plot(data.pca)

plotIndiv(data.pca, 
          group = Y,
          ind.names = F,
          legend = TRUE, 
          col.per.group = patient_kclust3_lab_conv,
          title = 'PCA on all NPX data')

#####
### PLS-Discriminant Analysis based on severity groups

data.plsda <- mixOmics::plsda(X, Y, ncomp = 10)
# takes a couple of minutes to run
perf.data.plsda <- perf(data.plsda, 
                        validation = "Mfold",
                        folds = 5,
                        progressBar = F,
                        auc = TRUE, 
                        nrepeat = 10) #100
################
(plot(perf.data.plsda, col = color.mixo(1:3), sd = TRUE, legend.position = "horizontal"))

## NULL
######
list.keepX <- c(1:10) # grid of possible keepX values that will be tested for each component
tune.splsda <- tune.splsda(X,
                           Y, 
                           ncomp = 3, 
                           validation = "Mfold",
                           folds = 5, 
                           progressBar = TRUE, 
                           dist = "centroids.dist",
                           measure = "BER",
                           test.keepX = list.keepX, 
                           nrepeat = 10, 
                           cpus = 8)
## 
## comp 1 
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |======================================================================| 100%
## comp 2 
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |======================================================================| 100%
## comp 3 
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |======================================================================| 100%
#####
## The classification error rates for each component conditional on the last component are represented below, for all components specified in the tune function.
plot(tune.splsda)

error <- tune.splsda$error.rate  # error rate per component for the keepX grid
ncomp <- tune.splsda$choice.ncomp$ncomp
ncomp
## [1] 1
ncomp = 2
#####
select.keepX <- tune.splsda$choice.keepX[1:ncomp]  # optimal number of variables to select
select.keepX
## comp1 comp2 
##    10     3
#####

splsda.data <- mixOmics::splsda(X, Y, ncomp = ncomp, keepX = select.keepX) 

#####

plotIndiv(splsda.data, 
          comp = c(1,2),
          group = Y, 
          ind.names = F, 
          ellipse = TRUE,
          #col.per.group =  patient_kclust3_lab,
          legend = T, 
          title = 'sPLS-DA on data, comp 1 & 2')

plotLoadings(splsda.data, comp = 1,ndisplay=20, title = 'Loadings on comp 1',legend.color =  patient_kclust3_lab_conv, 
             contrib = 'max', method = 'mean')

plotLoadings(splsda.data, comp = 2,ndisplay = 10, title = 'Loadings on comp 2', legend.color =  patient_kclust3_lab_conv, 
             contrib = 'max', method = 'mean')

auc.splsda <- auroc(splsda.data, roc.comp = 2, print = FALSE) # AUROC for the first component

auc.splsda$graph.Comp1
## NULL
auroc(splsda.data, roc.comp = 1, print = FALSE) 

Figure 6A

splsda.kclust.clusters <- plotIndiv(splsda.data, 
                                 comp = c(1,2),
                                 group = Y, 
                                 ind.names = F, 
                                 ellipse = TRUE,
                                 col.per.group = patient_kclust3_lab_conv,
                                 legend = F, 
                                 title = 'sPLS-DA on data, comp 1 & 2')

(splsda.kclust.clusters.ggplot <- splsda.kclust.clusters$df %>% 
    mutate(group = factor(group, levels=c("severe","moderate","mild","convalescence"))) %>%  
    
    ggplot(aes(x=x,y=y,color=group)) +
    ggforce::geom_mark_ellipse(aes(color = as.factor(group), fill=group),alpha=.1,show.legend = F, expand = unit(0.5,"mm")) +
    geom_point(size=0.5) + 
    scale_color_manual(values=patient_kclust3_lab_conv) +
    scale_fill_manual(values=patient_kclust3_lab_conv) +
    
    theme_minimal() +
    labs(title = "sparse PLS-DA",
         color= NULL,
         x=paste0("X-variate 1: ",round(splsda.data$prop_expl_var$X[[1]]*100,1),"% expl. var"),
         y=paste0("X-variate 2: ",round(splsda.data$prop_expl_var$X[[2]]*100,1),"% expl. var")) +
    theme(legend.position = "right") 
)

Figure 6B

plsda_loadings.df <-   
  data.frame(splsda.data$loadings$X) %>% 
  rownames_to_column("Assay") %>% 
  pivot_longer(names_to = "comp",values_to = "values",cols = -Assay) %>% 
  filter(values != 0,
         comp %in% c("comp1","comp2")) %>% 
  group_by(comp) %>% 
  mutate(values = scales::rescale(values, to=c(-1,1))) %>% 
  ungroup() 

(plsda_loadings.volcano.alt <-  plsda_loadings.df %>% 
    ggplot(aes(x=fct_reorder(Assay,values,.desc = T), y=values, color=comp,fill=comp)) +
    geom_point(size=0.5,alpha=1) +
    geom_col(width = 0.01) +
    coord_flip() +
    theme_minimal() +
    scale_color_manual(values=c(comp1 = "#1f78b4",comp2 = "#b2df8a")) +
    scale_fill_manual(values=c(comp1 = "#1f78b4",comp2 = "#b2df8a")) +
    labs(x="",
         fill=NULL,
         color=NULL,
         y="scaled loading values",
         title="sPLSDA loadings") +
    theme(legend.title = element_text(size=6),
          axis.text.x = element_text(size=6),
          legend.position = "right",
          legend.justification="right", 
          legend.box.spacing = unit(0, "pt")))

malaria.severity.siganture <- data.frame(splsda.data$loadings$X) %>% 
  rownames_to_column("Assay") %>% 
  pivot_longer(names_to = "comp",values_to = "values",cols = -Assay) %>% 
  filter(values != 0,
         comp %in% c("comp1")#,"comp2")
         )

Figure 6C

my_comparisons_severe_conv <- list(c("severe", "moderate"), c("moderate", "mild"), c("severe", "mild"),c("mild","convalescence"))

splsda.c1.top9 <- plsda_loadings.df %>% 
  filter(comp=="comp1") %>% 
  slice_min(n=9, order_by = values) %>% pull(Assay)# %>% 

(splsda.c1.top9 <- df_acute_patclust_incl_conv %>% 

    dplyr::filter(Assay %in% c(splsda.c1.top9)) %>% 
    mutate(Assay = factor(Assay, levels = c(splsda.c1.top9))) %>% 
    ggplot(aes(x=severity_lab, y=NPX, color=severity_lab, fill=severity_lab)) + 
    geom_violin(trim = F,alpha=.9) +
    geom_jitter(size=0.25,show.legend = F, width = 0.05, alpha=1, color="grey20") +
    geom_boxplot(alpha=.7,width=0.25,outlier.shape = NA,color="black", fatten = 2,lwd=.25,show.legend = F) +
    stat_compare_means(method = "wilcox.test",
                       label.sep = "\n",
                       hide.ns = T,
                       label = "p.signif" ,
                       vjust = .5,
                       size=2,
                       lwd = .2,
                       comparisons =my_comparisons_severe_conv,
                       show.legend = F) +
    facet_wrap(~Assay,ncol = 3,scales = "free_y") +
    theme_minimal() +
    theme(legend.position="bottom",
          axis.text.x = element_blank()) +
    labs(x="",
         color=NULL,
         fill=NULL) +
    scale_color_manual(values= patient_kclust3_lab_conv) +
    scale_fill_manual(values= patient_kclust3_lab_conv))

###plsda.selection <- data.frame(splsda.data$loadings$X) %>% 
#  rownames_to_column("Assay") %>% 
#  pivot_longer(names_to = "comp",values_to = "values",cols = -Assay) %>% 
#  filter(values != 0,
#         comp %in% c("comp1","comp2")) %>% 
#  pull(Assay)
plsda.selection <- malaria.severity.siganture %>% pull(Assay)

data.frame(Assay = plsda.selection) %>% 
  left_join(universe.proteins,by="Assay") %>% 
  transmute(Assay, UniProt)# %>% 
##       Assay UniProt
## 1     HMOX1  P09601
## 2     IL2RA  P01589
## 3      CD14  P08571
## 4     ICAM1  P05362
## 5   B4GALT1  P15291
## 6     CDCP1  Q9H5V8
## 7     CALCA  P01258
## 8  TNFRSF1B  P20333
## 9      RRM2  P31350
## 10     LAG3  P18627
  #write_tsv(paste0(result.dir,"MIP_Severity_Protein_signature_uniprotid.tsv"))

Figure 6D

## Explore 1536 data set - MGH Covid-19 study, Filbin et al. 2021

#### Make data ready

# identify proteins with NPX below LOD in more than 70% of samples
assays2rm <- covid_NPXdata %>% 
  mutate(belowLOD = LOD>NPX) %>% 
  group_by(Assay) %>% 
  count(belowLOD,sort=TRUE) %>% 
  filter(belowLOD==T,
         n > length(unique(covid_NPXdata$SampleID))*0.7) %>% 
  pull(Assay)

# remove proteins identified above from data
covid_NPXdata_rm <- covid_NPXdata %>% 
  filter(!Assay%in%assays2rm, Timepoint=="D0") %>%
  dplyr::select(SampleID, subject_id, Assay, NPX, Panel)

# identify proteins with different values in different panels
assays2rm <- covid_NPXdata_rm %>%
  group_by(subject_id, Assay) %>%
  summarise(n = n(), .groups = "drop") %>%
  filter(n > 1L) %>%
  pull(Assay) %>%
  unique()

# one example of the proteins identified above
covid_NPXdata_rm %>% filter(subject_id==1,Assay=="CXCL8")
## # A tibble: 4 × 5
##   SampleID subject_id Assay   NPX Panel          
##   <chr>         <dbl> <chr> <dbl> <chr>          
## 1 1_D0              1 CXCL8  1.46 CARDIOMETABOLIC
## 2 1_D0              1 CXCL8  4.40 INFLAMMATION   
## 3 1_D0              1 CXCL8  4.59 NEUROLOGY      
## 4 1_D0              1 CXCL8  3.52 ONCOLOGY
# convert data to wide format
covid_NPXdata_wide <- covid_NPXdata_rm %>%
  ## values_fn calculates median values for duplicated features (duplicated because part of every olink panel)
  pivot_wider(names_from = Assay, values_from = NPX,id_cols = subject_id, values_fn = median)

# make data ready for GSVA
covid_NPXdata_mat <- covid_NPXdata_wide %>%  
  column_to_rownames("subject_id") %>%
  as.matrix() %>% 
  t()
#### Run single sample gene set enrichment analysis

library(GSVA)

# run ssgsea on signature from sPLSDA
GSE_results <- gsva(expr = covid_NPXdata_mat,
                    gset.idx.list = list(sig=plsda.selection),verbose=F,
                    method="zscore")

#data_plot_sPLSDA <- data.frame(group=as.factor(covid_clinicalData$WHO.0),score=as.vector(GSE_results))

GSEA_result_df <- data.frame(subject_id = colnames(covid_NPXdata_mat),
                             ssES = as.vector(GSE_results)) %>% 
  right_join(mgh.covid.meta %>% transmute(subject_id= as.character(subject_id),
                                          who_0 = as.factor(who_0)), by="subject_id")

# show results
(MGH_covid_ssES <- GSEA_result_df %>% 
  ggplot(aes(x=who_0, y=ssES, fill=who_0)) +
    geom_jitter(width=0.15,size=.3,alpha=.2) +
 # geom_violin(width=1.5, trim = F, alpha=0.7,show.legend = F,lwd=.25) +
  geom_boxplot(width=.3,alpha=.6, fatten = 2,lwd=.25,outlier.colour = NA) +
  #geom_boxplot(alpha=0.6, width=.2, show.legend = F)+
  theme_minimal()+
    theme(legend.position = "none") +
  labs(y="ssES score (zscore)",x="Severity group",fill=""))

Figure 6E

#### Make data ready

MIP.long <- data.long %>% 
  left_join(sampleTable_simple) %>%
  filter(!grepl("D10",sample_id)) %>% 
    left_join(patient_clust) %>% 
  mutate(sample_type = case_when(Time=="Acute" ~ paste0(severity_lab," malaria"),
                                 .default = paste0(#Time,
                                   "Malaria",
                                   " convalescence"))) %>% 
  transmute(sample_id, sample_type, Assay, NPX)


data_tf_mip_wide <- TF.long %>% 
  bind_rows(MIP.long) %>% 
  pivot_wider(names_from = Assay, values_from = NPX, id_cols = c(sample_id,sample_type), values_fn = median) 

all.mat <- data_tf_mip_wide %>%
  dplyr::select(-c(sample_type)) %>% 
  column_to_rownames("sample_id") %>% 
  as.matrix() %>% 
  t()
#### Run single sample gene set enrichment analysis
library(GSVA)
# run ssgsea on signature from sPLSDA
GSE_results <- gsva(expr = all.mat,
                    gset.idx.list = list(sig=plsda.selection),#list(sig=severity_signature_proteins),
                    verbose=F,
                    method="zscore")


GSEA_result_df <- data.frame(sample_id = colnames(all.mat),
                             ssES = as.vector(GSE_results)) %>% 
  left_join(data_tf_mip_wide %>% dplyr::select(sample_id,sample_type), by="sample_id") %>% 
  left_join(
  TF_SOFA %>% transmute(sample_id = paste0(study_id,"|Acute"), SOFA_total) %>%
  bind_rows(
    subjectTable %>% transmute(sample_id = paste0(study_id,"|Acute"), SOFA_total)
  )) %>% 
  mutate(sample_type = case_when(sample_type == "Influensa A" ~ "Influenza A",
                                 sample_type == "Influensa B" ~ "Influenza B",
                                 .default = sample_type))

# show results

(TF_ssES_plot <- GSEA_result_df %>% 
ggplot(aes(x=fct_reorder(sample_type,ssES, median,.desc = T), y=ssES, fill=sample_type)) +
  geom_jitter(width=0.15,size=.3,alpha=.2) +
  geom_boxplot(width=.3,alpha=.6, fatten = 2,lwd=.25,outlier.colour = NA) +
  theme_minimal() +
    scale_fill_manual(values=c("severe malaria"=patient_kclust3_lab[[3]],
                               "moderate malaria"=patient_kclust3_lab[[2]],
                               "mild malaria"=patient_kclust3_lab[[1]],
                               "Malaria convalescence"=patient_kclust3_lab_conv[[4]]),
                      na.value = "#8dd3c7") +
  geom_hline(yintercept = 0,linetype="dotted") +
  labs(title="Evaluation of malaria disease severity signature",
       x=NULL,
       y="Gene Set Variation Analysis\nsingle sample enrichment score\n(zscore)",
       fill="") +
    theme(legend.position = "none") +
      scale_x_discrete(labels = label_wrap(8)) )

Supplementary Table S5

malaria.severity.siganture %>% 
  arrange(values) %>% 
  dplyr::rename(importance = values) %>% 
  head()
## # A tibble: 6 × 3
##   Assay    comp  importance
##   <chr>    <chr>      <dbl>
## 1 TNFRSF1B comp1     -0.611
## 2 B4GALT1  comp1     -0.576
## 3 IL2RA    comp1     -0.391
## 4 ICAM1    comp1     -0.252
## 5 HMOX1    comp1     -0.202
## 6 RRM2     comp1     -0.140
  #write_tsv(paste0(result.dir,"Supplementary_TableS5_SeveritySignature.tsv"))

Supplementary Table S6

TF cohort - sampleTable

##gtsummary
library(gtsummary)

TF_sampleTable %>% 
  dplyr::select(-sample_type) %>% 
  inner_join(GSEA_result_df, by="sample_id") %>% 
  transmute(sample_type, 
            SOFA_total = as.numeric(SOFA_total),
            age = as.numeric(age),
            gender) %>% 
  filter(!grepl("Malaria|malaria", sample_type)) %>% 
  
  tbl_summary(include = c(sample_type, age, gender,
                          SOFA_total),
              by = sample_type,
              statistic = list(all_continuous() ~ "{median} ({min}-{max})",
                               all_categorical() ~ "{n} / {N} ({p}%)"
              ),
              #digits = all_continuous() ~ 2
              digits = c(age ~ 0)
              )
Characteristic Campylobacter, N = 171 Dengue, N = 191 E.coli -pyelonefriter, N = 91 Influenza A, N = 171 Influenza B, N = 181 Mycoplasma pneumonier, N = 51 Salmonella (only feces), N = 121 Shigella, N = 31
age 32 (26-61) 34 (22-66) 56 (24-87) 45 (23-88) 38 (26-68) 40 (18-72) 38 (22-61) 40 (29-50)
gender 11 / 17 (65%) 11 / 19 (58%) 2 / 9 (22%) 5 / 17 (29%) 7 / 18 (39%) 3 / 5 (60%) 8 / 12 (67%) 1 / 3 (33%)
SOFA_total
    0 15 / 17 (88%) 12 / 19 (63%) 4 / 5 (80%) 14 / 17 (82%) 15 / 18 (83%) 3 / 4 (75%) 11 / 12 (92%) 2 / 3 (67%)
    1 2 / 17 (12%) 3 / 19 (16%) 0 / 5 (0%) 3 / 17 (18%) 1 / 18 (5.6%) 1 / 4 (25%) 1 / 12 (8.3%) 0 / 3 (0%)
    2 0 / 17 (0%) 4 / 19 (21%) 0 / 5 (0%) 0 / 17 (0%) 2 / 18 (11%) 0 / 4 (0%) 0 / 12 (0%) 1 / 3 (33%)
    3 0 / 17 (0%) 0 / 19 (0%) 1 / 5 (20%) 0 / 17 (0%) 0 / 18 (0%) 0 / 4 (0%) 0 / 12 (0%) 0 / 3 (0%)
    Unknown 0 0 4 0 0 1 0 0
1 Median (Minimum-Maximum); n / N (%)

Figure 7

A protein-centric view on integrated analysis to ascertain immune cell communication associated with disease severity

Figure 7A

similar_modules <- c(restricted_module_turquoise,
                     module_df %>% filter(colors=="brown") %>% pull(Assay),
                     module_df %>% filter(colors=="blue") %>% pull(Assay))
library(eulerr)
euler_plot <- euler(
  list(
    "Differential\nabundant\nproteins\nin\nacute malaria"=selected.assays.wcna,
    "Severity associated\nproteins in plasma" = restricted_module_turquoise)
)

plot(euler_plot,
     fills = c("white",
               "turquoise"),
               
     quantities = TRUE,
     lty = 1,#1:3,
     fontsize=6,
     labels = list(fontsize=5),
     shape = "ellipse") 

Figure 7B

secretome_location_dap_severity <- dap.res %>% 
  filter(Assay %in% restricted_module_turquoise) %>% 
  inner_join(hpa_24.0, by=c("Assay"="gene","UniProt"="uniprot")) %>% 
  mutate(secretome_location_tissue_spec = case_when(secretome_location=="Not secreted"~ paste0(secretome_location," - ",rna_tissue_specificity),
                                                   .default = secretome_location)) %>% 
  group_by(secretome_location_tissue_spec) %>% 
 mutate(n_secretome_location_tissue_spec = n()) #count(sort = TRUE) 


## plot everything
(hpa.protein.origin.overview_severity <- secretome_location_dap_severity %>% 
    ungroup() %>% 
    transmute(secretome_location_tissue_spec = factor(secretome_location_tissue_spec,
                                                     levels = rev(c("Secreted to blood",
                                                                    "Intracellular and membrane",
                                                                    "Secreted in other tissues",
                                                                    "Secreted to extracellular matrix",  
                                                                    "Secreted to digestive system", 
                                                                    "Secreted in brain",
                                                                    "Secreted - unknown location",
                                                                    "Secreted in female reproductive system",
                                                                    "Secreted in male reproductive system",
                                                                    "Not secreted - Tissue enriched", 
                                                                    "Not secreted - Tissue enhanced",
                                                                    "Not secreted - Group enriched",
                                                                    "Not secreted - Low tissue specificity"))),
              n_secretome_location_tissue_spec) %>% 
    distinct() %>% 
    ggplot(aes(x = secretome_location_tissue_spec, y = n_secretome_location_tissue_spec, fill = secretome_location_tissue_spec)) +
    geom_col(width = 0.5) +
    geom_text(aes(label=n_secretome_location_tissue_spec),size=2, nudge_y = -.2) +
    coord_flip() +
    scale_y_continuous(trans="pseudo_log",name = "Number of proteins\nassociated with severity",
                       sec.axis = sec_axis(~.,labels = NULL,breaks = NULL,
                                           #name = "Number of DAPs"
                                           ), 
                       #expand=c(0,.15)
                       expand = c(0,0)
                       ) +
    theme_bw() +
    theme(axis.text.y = element_text(size = 6),
          axis.text.x = element_text(size = 6),
          legend.text=element_text(size=6),
          legend.title=element_text(size=6),
          plot.title = element_text(size=6),
          legend.position = "none")+

    scale_fill_manual(values=secretome_location_tissue_spec_cols,
                      limits = secretome_location_dap.order) +
    labs(fill="Protein\norigin\nby HPA",
         x=NULL))

## plot everything
(hpa.protein.origin.overview_severity <- secretome_location_dap_severity %>% 
    ungroup() %>% 
    transmute(secretome_location_tissue_spec = factor(secretome_location_tissue_spec,
                                                     levels = c("Secreted to blood",
                                                                    "Intracellular and membrane",
                                                                    "Secreted in other tissues",
                                                                    "Secreted to extracellular matrix",  
                                                                    "Secreted to digestive system", 
                                                                    "Secreted in brain",
                                                                    "Secreted - unknown location",
                                                                    "Secreted in female reproductive system",
                                                                    "Secreted in male reproductive system",
                                                                    "Not secreted - Tissue enriched", 
                                                                    "Not secreted - Tissue enhanced",
                                                                    "Not secreted - Group enriched",
                                                                    "Not secreted - Low tissue specificity")),
              n_secretome_location_tissue_spec) %>% 
    distinct() %>% 
    ggplot(aes(x = secretome_location_tissue_spec, y = n_secretome_location_tissue_spec, fill = secretome_location_tissue_spec)) +
    geom_col(width = 0.5) +
    geom_text(aes(label=n_secretome_location_tissue_spec),size=2, nudge_y =1.5) + #0.1
    #coord_flip() +
    scale_y_continuous(#trans="pseudo_log",
                       name = "Number of proteins",
                       sec.axis = sec_axis(~.,labels = NULL,breaks = NULL,
                                           #name = "Number of DAPs"
                                           ), 
                       #expand=c(0,.15)
                       #expand = c(0,0.1),
                       limits = c(0,51)
                       ) +
    theme_bw() +
    theme(axis.text.y = element_text(size = 6),
          axis.text.x = element_text(size = 6,angle=90,hjust = 1,vjust = 0.5),
          #axis.text.x = element_text(size = 6,angle=45,hjust = 1),
          axis.title.y = element_text(size=6),

          legend.text=element_text(size=6),
          legend.title=element_text(size=6),
          plot.title = element_text(size=6),
          legend.position = "none")+

    scale_fill_manual(values=secretome_location_tissue_spec_cols,
                      limits = secretome_location_dap.order) +
    labs(fill="Protein\norigin\nby HPA",
         x=NULL))

Figure 7C

proteins2label <- df_acute_patclust_incl_conv %>% 
  group_by(UniProt,Assay, severity_lab) %>% 
  summarise(NPXmean = mean(NPX),
            NPXmedian = median(NPX),
            NPXsd = sd(NPX),
            NPXn = n(),
            NPXse = NPXsd / sqrt(NPXn)
  ) %>% 
  #ungroup() %>% 
  mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
  left_join(
    secretome_location_dap_severity %>%
    filter(Assay %in% restricted_module_turquoise) %>%
  transmute(Assay,secretome_location_tissue_spec), by="Assay"
  ) %>% 
  filter(severity_lab=="severe",
         Assay %in% restricted_module_turquoise,
         !is.na(secretome_location_tissue_spec)) %>% 
  
  group_by(secretome_location_tissue_spec) %>% 
  #transmute(Assay,NPX, severity_lab, secretome_location_tissue_spec) %>% 
  distinct() %>% 
  slice_max(order_by = NPXmean,n = 3) %>% pull(Assay)
tmp.df <- df_acute_patclust_incl_conv %>% 
  group_by(UniProt,Assay, severity_lab) %>% 
  summarise(NPXmean = mean(NPX),
            NPXmedian = median(NPX),
            NPXsd = sd(NPX),
            NPXn = n(),
            NPXse = NPXsd / sqrt(NPXn)
  ) %>% 
  #ungroup() %>% 
  mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
  filter(Assay%in%restricted_module_turquoise) %>% 
  left_join(
    secretome_location_dap_severity%>% 
      transmute(Assay, secretome_location_tissue_spec), by="Assay")

(turqoise_allProteins_lab <- tmp.df %>% 
  ggplot(aes(x=fct_reorder(Assay,NPXmean,.desc = F), y=NPXmean)) +
  geom_point(shape=16,size=.5,aes(color=severity_lab)) +
  geom_errorbar(aes(x = Assay,#reorder(str_wrap(Assay, 5), estimate),
                    ymin=NPXmean-NPXci95, 
                    ymax=NPXmean+NPXci95,
                    color=severity_lab),
                linewidth=.2,    # Thinner lines
                width=.2,
                alpha=.5) +
  geom_hline(yintercept = 0,lty=5, lwd=.2) +
    ggrepel::geom_text_repel(data = . %>% filter(Assay %in% proteins2label,#c("LGALS9","HAVCR2","IL4","IL4R","CD70","PDCD1","CD274"),
                                                 severity_lab == "severe"),
                             aes(label = Assay, colour=secretome_location_tissue_spec, nudge_y=NPXmean),
                             size = .9,
                             force_pull = 3, # do not pull toward data points
                             force = .15, # Strength of the repulsion force.

                             nudge_x = 0,
                             # Do not repel from top or bottom edges.
                             ylim = c(1, Inf),
                             direction    = "y",
                             angle        = 90,
                             hjust        = 0,
                             segment.size = 1/20,    ## segment width
                             segment.linewidth = 1/12,#0.01,
                             arrow = arrow(length = unit(0.04, 'npc')),     # Draw an arrow from the label to the data point.
                             
                             
                             max.overlaps = 50,
                             max.iter = 3e3,     # Maximum iterations of the naive repulsion algorithm O(n^2).
                             color = "grey10"
  ) +
  scale_y_continuous(limits=c(-1.5,8.5),expand = c(0,0)) +
  scale_color_manual(values = patient_kclust3_lab_conv) +
      coord_cartesian(clip = "off") +

  #coord_flip() +
  
  labs(x="Severity associated proteins in plasma",
       y="NPX",
       color=NULL,
       caption = "meanNPX +- ci95") +
  theme(legend.position = "top",
        axis.text.x = element_text(colour = "black",angle=90,hjust=1,vjust=.5,size = 2),
        axis.text.y = element_text(size = 6),
        panel.grid.minor = element_line(size = 0.1),
        panel.grid.major = element_line(size = .1),
        #axis.text.x = element_blank()
        )
)

require(patchwork)
(p_annotation <- #secretome_location_dap_severity%>% 
    #transmute(Assay, secretome_location_tissue_spec) %>% 
   # left_join(tmp.df,by="Assay") %>% 
    tmp.df %>% 
    mutate(dummy.y = "HPA") %>% 
    ggplot(aes(x = fct_reorder(Assay,NPXmean,.desc = F), y = dummy.y, fill = secretome_location_tissue_spec)) +
    geom_tile(linejoin = "round") +
    scale_fill_manual(values = secretome_location_tissue_spec_cols) +
    theme_void() +
    theme(legend.position = "none") 
  #scale_y_discrete(expand=c(0,-0.1))
   # theme(aspect.ratio = 1/100)
  )

test_plot <- p_annotation / turqoise_allProteins_lab + plot_layout(height = c(.5, 4))
test_plot

Figure 7D

## create a gene name - uniprot dictionary
name_up_dict <- hpa_24.0 %>% transmute(gene, uniprot)

ligand.q <- dap.res %>% filter(p.adj <=0.01, logFC > .1) %>% 
  left_join(cpdb.protein_input,
            by=c("UniProt"="uniprot")) #%>% 
  #pull(UniProt)

length(ligand.q)
## [1] 32
interaction_dict <- cpdb.interaction_input %>% 
  filter(partner_a %in% ligand.q$UniProt,
         directionality == "Ligand-Receptor"
        #directionality %in% c("Ligand-Receptor","Receptor-Receptor","Ligand-Ligand")
         ) %>% 
  mutate(protein_name_b_strip = gsub("_HUMAN","",protein_name_b),
         protein_name_a = gsub("_HUMAN","",protein_name_a)) %>% 
  mutate(protein_name_b_complex = case_when(is.na(protein_name_b) ~ str_remove(interactors,paste0(protein_name_a,"-")),
                                    .default = protein_name_b)) %>%
   separate_longer_delim(protein_name_b_complex, delim = "+") %>% 
   left_join(hpa_24.0 %>% transmute(protein_name_b_complex = gene,
                                      uniprot_b_complex = uniprot), by=c("protein_name_b_complex")) %>% 
  mutate(protein_name_b = case_when(is.na(protein_name_b) ~ protein_name_b_complex,
                                        .default = protein_name_b),
         partner_b_new = case_when(is.na(uniprot_b_complex) ~ partner_b,
                                   .default = uniprot_b_complex)) %>% 
  transmute(partner_a, partner_b, partner_b_new) %>% 
  mutate(uniprot_a = partner_a,
         uniprot_b = partner_b_new) %>% 
  transmute(source = uniprot_a,
            recipient = uniprot_b) %>% 
  left_join(name_up_dict %>% dplyr::rename(source_gene = gene), by=c("source" = "uniprot")) %>% 
  left_join(name_up_dict %>% dplyr::rename(recipient_gene = gene), by=c("recipient" = "uniprot"))
interaction_dict
## # A tibble: 262 × 4
##    source recipient source_gene recipient_gene
##    <chr>  <chr>     <chr>       <chr>         
##  1 P19022 P06734    CDH2        FCER2         
##  2 P05362 P20701    ICAM1       ITGAL         
##  3 P05362 P20701    ICAM1       ITGAL         
##  4 P05362 P05107    ICAM1       ITGB2         
##  5 P05362 P11215    ICAM1       ITGAM         
##  6 P05362 P05107    ICAM1       ITGB2         
##  7 P05362 P20702    ICAM1       ITGAX         
##  8 P05362 P05107    ICAM1       ITGB2         
##  9 P13598 Q9NNX6    ICAM2       CD209         
## 10 P13598 P20701    ICAM2       ITGAL         
## # ℹ 252 more rows
celltype_l2_freq <- tibble(pbmc_acute@meta.data) %>% 
  group_by(CellType_L2) %>% 
  summarise(n = n()) %>%
  mutate(freq = n / sum(n),
         Percentage = freq*100) 

celltype_l2_of_l1_freq <- tibble(pbmc_acute@meta.data) %>% 
  group_by(CellType_L1,CellType_L2) %>% 
  summarise(n = n()) %>%
  group_by(CellType_L1) %>% 
  mutate(freq = n / sum(n),
         Percentage = freq*100) 

circosplot function

my_nice_circosplot <- function(assays2plot_circos, scale_range, expression_threshold, pdf_file_name){
  
pbmc_acute.avg.long_tourquoise <- pbmc_acute.avg.long %>% 
  filter(celltype != "undefined",
         gene %in% assays2plot_circos,
         ) %>% 
  mutate(gene_ct = paste0(gene,"_",celltype)) %>% 
  group_by(gene) %>% 
  mutate(avgExp = scales::rescale(avgExp, to=scale_range)) %>%  #c(0,1)
  ungroup() 

mat <- pbmc_acute.avg.long_tourquoise %>% 
    filter(avgExp >expression_threshold) %>% #.5
  left_join(tibble(pbmc@meta.data) %>% transmute(celltype_1 = CellType_L1,
                                                celltype = CellType_L2) %>% distinct(), by="celltype") %>% 
  mutate(celltype_1 = factor(celltype_1, levels= c("DC","Monocytes","NK","gdT","B","CD4+ T","CD8+ T")),
         celltype = factor(celltype, levels = c("mDC", "pDC", 
                                                "CD14 monocytes", "CD16 monocytes",
                                                "NK CD56dim CD16+", "NK CD56dim","NK CD56bright","NK prolif.",
                                                "Vd2+ gdT", "Vd2- gdT",
                                                "B naive", "B memory", "Plasma cells",
                                                "CD4 naive", "CD4 Treg CD80+", "CD4 Treg CD80-", "CD4 Tfh",
                                                "CD4 effect. activated", "CD4 effect. memory",
                                                "CD4 trans. memory","CD4 central memory",
                                                "CD8 naive", "CD8 trans. memory", "CD8 Tfh",
                                                "NKT", "CD8 effect. memory"))) %>% 
  add_rownames() 


tmp <- mat %>% dplyr::rename(index = rowname) 

df_link <- interaction_dict %>% 
  transmute(source_gene, recipient_gene) %>% 
  left_join(tmp %>% 
               filter(gene %in% interaction_dict$source_gene) %>%
               transmute(from_index = index,
                         gene), 
             by=c("source_gene"="gene")) %>% 
  filter(!is.na(from_index)) %>% 
  left_join(tmp %>% 
               transmute(to_index = index,
                         gene), 
             by=c("recipient_gene"="gene")) %>% 
  filter(!is.na(to_index)) %>% 
  distinct() %>% 
  right_join(mat %>% transmute(gene, celltype) %>% 
               left_join(data.frame(celltype = names(L2_colors), 
                                    source_celltype_colors = L2_colors)),
              by=c("source_gene"="gene")) %>% 
  
  transmute(from_index = as.integer(from_index),
            to_index = as.integer(to_index),
            source_celltype = celltype,
            source_gene,
            recipient_gene) %>% 
  na.omit() %>% 
  distinct()

## goal
## from_index; to_index data frame


mat_gex <- mat %>% arrange(celltype) %>%
  column_to_rownames("gene_ct") %>% 
  dplyr::select(avgExp)

mat_npx <- mat %>%
  transmute(gene_ct, gene) %>% 
  left_join(df_acute_patclust_incl_conv %>% 
              transmute(Assay, NPX,severity_lab) %>% 
              #filter(Assay %in% restricted_module_turquoise) %>% 
              pivot_wider(names_from = severity_lab, values_from = NPX,values_fn = median)
            , by=c("gene"="Assay")) %>% 
  dplyr::select(-gene) %>% 
  distinct() %>%
  column_to_rownames("gene_ct") %>%
  relocate(severe, moderate, mild, convalescence)


## legends
col_npx <- colorRamp2(c(min(mat_npx,na.rm = T),
                        0,
                        max(mat_npx,na.rm = T)/2,
                        max(mat_npx,na.rm = T)),
                      c("#edf8e9","#bae4b3", "#74c476","#238b45"))

#mat_npx <- mat_npx %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(4,0))))
cell_freq_color <- colorRamp2(c(0,
                                min(celltype_l2_freq$Percentage,na.rm = T),
                                mean(celltype_l2_freq$Percentage,na.rm=T),
                                max(celltype_l2_freq$Percentage,na.rm = T)),
                              c("#f2f0f7","#cbc9e2","#9e9ac8","#6a51a3"))

lgd_npx = Legend(title = "NPX", col_fun = col_npx,
                 title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

lgd_gex = Legend(title = "GEX", col_fun = scaled_01_col,
                 title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

lgd_celltype_freq = Legend(title = "Cell frequency\nof CD45+",
                           col_fun = cell_freq_color,
                 title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

lgd_severity = Legend(title = "Severity group", 
                      at = c("severe","moderate","mild","convalescence"),
                      legend_gp = gpar(fill = c("#ca0020","#f4a582","#92c5de","grey50")),
                      title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))


lgd_celltype = Legend(title = "Celltypes", 
                      at = c("DC","Monocytes","NK","gdT","B","CD4+ T","CD8+ T"),
                      legend_gp = gpar(fill = c("#ca5369","#688bcc","#8761cc", "#ae953e",
                                                "#c361aa","#68a748","#cc693d")),
                      ncol = 1,
                      #nrow = 1,
                      title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

lgd_celltype_2 = Legend(title = "Celltypes", 
                      at = c("mDC","pDC",
                             "CD14 monocytes","CD16 monocytes",
                             "NK CD56dim CD16+","NK CD56dim","NKCD56bright","NK prolif.","NKT",
                             "Vd2+ gdT","Vd2- gdT",
                             "B naive",
                             "B memory",
                             "Plasma cells",
                             "CD4 naive", "CD4 Treg CD80+", "CD4 Treg CD80-", "CD4 Tfh",
                             "CD4 effect. activated","CD4 effect. memory","CD4 trans.memory","CD central memory",
                             "CD8 naive", "CD8 trans. memory","CD8Tfh","CD8 effect. memory"),
                             #,(L2_colors),
                      legend_gp = gpar(fill = L2_colors),
                      
                      ncol=1,
                      #nrow = 4,
                      title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

circle_size = unit(1, "snpc") # snpc unit gives you a square region

## == circos.heatmap.get.x start ====

## A function to extract row indicies, useful for labelling

## source: https://rdrr.io/github/jokergoo/circlize/src/R/circos.heatmap.R
# == title
# Get the x-position for heatmap rows
#
# == param
# -row_ind A vector of row indicies.
#
# == value
# A three-column data frame of the sector, the x-positions on the corresponding sectors, and the original row indicies.
circos.heatmap.get.x = function(row_ind) {
    env = circos.par("__tempenv__")
    split = env$circos.heatmap.split

    row_ind_lt = split(row_ind, split[row_ind])
    row_ind_lt = row_ind_lt[sapply(row_ind_lt, length) > 0]
    
    x = NULL
    for(i in row_ind_lt) {

        subset = get.cell.meta.data("subset", sector.index = split[i[1]])
        order = get.cell.meta.data("row_order", sector.index = split[i[1]])
        
        x = c(x, which((1:length(split))[subset][order] %in% i))
    }
    df = data.frame(sector = rep(names(row_ind_lt), times = sapply(row_ind_lt, length)), 
        x = x - 0.5, row_ind = unlist(row_ind_lt))
    rownames(df) = NULL
    df
}
## == circos.heatmap.get.x end ====

total_sections <- length(levels(mat$celltype))


## the function to make the plot
circlize_plot = function() {
    circos.clear()

  circos.par(gap.after = c(rep(2,total_sections-1),10), 
             points.overflow.warning = T)
#circos.par(start.degree = 90, gap.degree = 10,gap.after = c(3))

## dummy track, invisible, needed for split
circos.heatmap(mat_gex,
               cluster = F,
               split = droplevels(mat$celltype),
               col = colorRamp2(c(-2, 0, 2), c("white", "white", "white")), 
               track.height = 0.21,#0.000000001,
               )

## celltype annotation track
circos.heatmap(mat %>% column_to_rownames("gene_ct") %>% dplyr::select(celltype), 
               col = L2_colors, 
               track.height = 0.08,
               rownames.side = "none",
 )

## celltype frequency track
circos.heatmap(mat %>% column_to_rownames("gene_ct") %>% transmute(CellType_L2 = celltype) %>% left_join(celltype_l2_freq, by="CellType_L2") %>% pull(Percentage), col = cell_freq_color, track.height = 0.01)

## celltype annotation tack naming
circos.trackPlotRegion(track.index = 1, panel.fun = function(x, y) {
  xlim = get.cell.meta.data("xlim")
  ylim = get.cell.meta.data("ylim")
  sector.name = get.cell.meta.data("sector.index")
  circos.text(mean(xlim),
              ylim[1] + .1, 
              sector.name, 
              facing = "clockwise", 
              niceFacing = TRUE, cex=.6,
              adj = c(0, 0.5), col = "grey40")
}, bg.border = NA)

## celltype gene expression track
circos.heatmap(mat_gex,
               cluster = F, 
               col = scaled_01_col, 
               track.height = 0.04,
               # rownames.side = "outside",
               bg.border = "grey80", 
               bg.lwd = .1,
               bg.lty = .1, 
               show.sector.labels = F
)

## plasma NPX trac
circos.heatmap(mat_npx, col = col_npx, track.height = 0.09)

## add annotation to row of npx data
circos.track(track.index = get.current.track.index(), panel.fun = function(x, y) {
    if(CELL_META$sector.numeric.index == total_sections) { # the last sector #26
      ## conval
        circos.rect(CELL_META$cell.xlim[2] + convert_x(1, "mm"), 0,
                    CELL_META$cell.xlim[2] + convert_x(4, "mm"), 1, #10
                    col = "grey50", border = NA)
      ## mild  
      circos.rect(CELL_META$cell.xlim[2] + convert_x(1, "mm"), 1,
                    CELL_META$cell.xlim[2] + convert_x(4, "mm"), 2, #5
                    col = "#92c5de", border = NA)
      ## moderate
        circos.rect(CELL_META$cell.xlim[2] + convert_x(1, "mm"), 2,
                    CELL_META$cell.xlim[2] + convert_x(4, "mm"), 3, #10
                    col = "#f4a582", border = NA)
        ## severe
        circos.rect(CELL_META$cell.xlim[2] + convert_x(1, "mm"), 3,
                    CELL_META$cell.xlim[2] + convert_x(4, "mm"), 4, #10
                    col = "#ca0020", border = NA)
       
    }
}, bg.border = NA)

## Annotate source genes
row_ind <- mat %>% filter(gene%in%df_link$source_gene) %>% mutate(rowname = as.integer(rowname)) %>% pull(rowname)
pos_so = circos.heatmap.get.x(row_ind)
pos_so <- pos_so %>% right_join(mat %>% filter(gene%in%df_link$source_gene) %>% mutate(row_ind = as.integer(rowname)), by="row_ind")

## Annotate recipient genes
row_ind <- mat %>% filter(gene%in%df_link$recipient_gene) %>% mutate(rowname = as.integer(rowname)) %>% pull(rowname)
pos_rec = circos.heatmap.get.x(row_ind)
pos_rec <- pos_rec %>% right_join(mat %>% filter(gene%in%df_link$recipient_gene) %>% mutate(row_ind = as.integer(rowname)), by="row_ind")

pos <- bind_rows(pos_so, pos_rec)

## lable all other genes

## Annotate source genes
row_ind_allothers <- mat %>% filter(!gene %in% c(df_link$source_gene,df_link$recipient_gene)) %>% mutate(rowname = as.integer(rowname)) %>% pull(rowname)

pos_allothers = circos.heatmap.get.x(row_ind_allothers) %>% 
  left_join(mat %>% mutate(row_ind = as.integer(rowname)), by="row_ind")

## join all lable info
pos_all <- bind_rows(pos %>% mutate(col = "black",
                                    size = .4),
                     pos_allothers %>% mutate(col = "grey",
                                              size=.2))

circos.labels(pos_all$sector, 
              pos_all$x,
              connection_height =.01,
              cex =pos_all$size,
              side="inside",
              col = pos_all$col, 
              labels = pos_all$gene)

## add connections
for(i in seq_len(nrow(df_link))) {

        circos.heatmap.link(df_link$from_index[i],
                        df_link$to_index[i],
                        col = rand_color(1),
                        
                        lwd = 1.5,
                        directional = 1,
                        arr.width = .125,
                        arr.length = .2,
                        arr.lwd = .1,
                       arr.col = "black")
}


  circos.clear()
}

library(gridBase)
pdf(paste0(result.tmp.dir,pdf_file_name,".pdf"))#,paper = "a4r")
plot.new()

circle_size = unit(1, "snpc") # snpc unit gives you a square region

pushViewport(viewport(x = 0.5, y = 1,#0.5,
                      width = circle_size, 
                      height = circle_size,
    just =  c("center", "top")))
par(omi = gridOMI(), new = TRUE)
circlize_plot()
upViewport()

draw(packLegend(lgd_gex, lgd_npx,
                direction = "horizontal"),
     y = unit(1, "npc") - circle_size*.1, 
     x = unit(1.04,"npc") - circle_size*0.1,
     just = c("center","right"))

draw(packLegend(lgd_celltype_freq,
                direction = "horizontal"),
     #y = unit(1, "npc") - circle_size*.1, 
     x = unit(1.04,"npc") - circle_size*0.1,
     just = c("center","right"))


draw(packLegend(lgd_severity,
                direction = "horizontal"),
     y = unit(1, "npc") - circle_size*.8, 
     x = unit(1.0,"npc") - circle_size*0.11,
     just = c("bottom","left"))
dev.off()
return(circlize_plot())
}
my_nice_circosplot(assays2plot_circos = restricted_module_turquoise,
                   scale_range = c(0,1),
                   expression_threshold = 0.5,
                   pdf_file_name = "ImmuneCell_Protein_CircosPlot_severitymodule"
                   )

Figure 7E

my_comparisons_severe_conv <- list(c("severe", "moderate"), c("moderate", "mild"), c("severe", "mild"),c("mild","convalescence"))

selection <- c("LGALS9","IL4","CD274","CD70")

(severity_ligand_npx <- df_acute_patclust_incl_conv %>% 

    dplyr::filter(Assay %in% c(selection)) %>% 
    mutate(Assay = factor(Assay, levels = c(selection))) %>% 
    ggplot(aes(x=severity_lab, y=NPX, color=severity_lab, fill=severity_lab)) + 
    geom_violin(trim = F,alpha=.9) +
    geom_jitter(size=0.25,show.legend = F, width = 0.05, alpha=1, color="grey20") +
    geom_boxplot(alpha=.7,width=0.25,outlier.shape = NA,color="black", fatten = 2,lwd=.25,show.legend = F) +
    stat_compare_means(method = "wilcox.test",
                       label.sep = "\n",
                       hide.ns = T,
                       label = "p.signif" ,
                       vjust = .5,
                       size=2,
                       lwd = .2,
                       comparisons =my_comparisons_severe_conv,
                       show.legend = F) +
    facet_wrap(~Assay,nrow = 2,scales = "free_y") +
    theme_minimal() +
    theme(legend.position="bottom",
          axis.text.x = element_blank()) +
    labs(x="",
         color=NULL,
         fill=NULL) +
    scale_color_manual(values= patient_kclust3_lab_conv) +
    scale_fill_manual(values= patient_kclust3_lab_conv))

Figure 7F

#FACs_data %>% distinct(feature)

cellsubset.order <- FACs_data %>% 
  filter(feature%in%c("CD4+CD38+HLADR+ T cells","CD8+CD38+HLADR+ T cells"),
#    grepl("Treg",feature)
    ) %>% distinct(feature) %>% pull()

test_correlation_input <- FACs_data %>% 
  filter(Time=="Acute",
         feature%in%
           c(
           "CD4+CD38+HLADR+ T cells",
           "CD8+CD38+HLADR+ T cells"
         )
  ) %>% 
  transmute(sample_id = sampleID,
            type_feature = paste0("FACS_",feature),
            value) %>% 
  pivot_wider(values_from = value, names_from = type_feature) %>% 
  inner_join(
    ## Plasma protein data from this paper
    data.long %>% 
      inner_join(sampleTable_simple) %>% 
      filter(Assay %in% restricted_module_turquoise) %>% 
      transmute(
        sample_id,
        type_assay = paste0("PEA_",Assay),
        NPX) %>% 
      pivot_wider(values_from = NPX, names_from = type_assay),
    by="sample_id")
test_correlation_res <- test_correlation_input %>% 
  column_to_rownames("sample_id") %>% 
  correlation(p_adjust = "fdr",method = "spearman",redundant = F) %>% 
  tibble()
cor.g <- test_correlation_res %>% 
  filter(Parameter1!=Parameter2) %>% 
  filter(
    !grepl("PEA",Parameter1),
    !grepl("FACS",Parameter2)
  ) %>% 
   arrange(-abs(rho)) %>% 
  filter(p<=0.05) %>% 
     transmute(from = Parameter1,# = str_remove(Parameter1, "FACS_"),
            to = Parameter2,# = str_remove(Parameter2, "PEA_"),
            rho,
            p
            ) %>% 
  as_tbl_graph(directed = F)

node_table <- as_tibble(cor.g) %>% 
  separate(name, into=c("omics","feature"),sep = "_",remove = F) 
(protein_cellnum_cornet <- cor.g %>% 
  inner_join(node_table,by="name") %>% 
    activate(nodes) %>%  # Sets context to nodes -> subsequent operations are performed on nodes
  mutate(deg = centrality_degree()) %>% 
  filter(!node_is_isolated()) %>%  # Removes nodes that are isolated/do not have any follower edges
# create_layout(layout = "igraph", algorithm = "fr") %>% 
  create_layout(layout = "stress") %>%  #fr
  ggraph() +
    geom_edge_link(aes(color = rho),
                   #    alpha = 0.9
                   ) +  
  scale_edge_color_continuous(low="thistle2",
                              high="darkred") +
  geom_node_point(aes(color = omics,
                      size= ifelse(omics=="FACS",3,1)),
                  show.legend = F) +
  geom_node_text(aes(label = feature,
                     alpha= ifelse(deg>1,1,.5)
                     ),
                 color="black",
                 size=1.5,
                 repel = T,show.legend = F
                     ) +
  scale_alpha_continuous(range = c(0.5, 1)) +
  theme_void() +
    guides(color= guide_colorbar(barheight = 1, barwidth = .1)) +

   theme(legend.position = "right",
         plot.title = element_text(size=6),
         legend.title = element_text( size=6),
         legend.text=element_text(size=6)) 

)

Session Info

sessionInfo()
## R version 4.3.2 (2023-10-31)
## Platform: aarch64-apple-darwin20 (64-bit)
## Running under: macOS Sonoma 14.7.4
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: Europe/Stockholm
## tzcode source: internal
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] gridBase_0.4-7        GSVA_1.48.3           UpSetR_1.4.0         
##  [4] see_0.8.0             pathview_1.40.0       ggtext_0.1.2         
##  [7] gtsummary_1.7.2       emmeans_1.8.7         lmerTest_3.1-3       
## [10] lme4_1.1-34           eulerr_7.0.2          mixOmics_6.24.0      
## [13] lattice_0.21-8        MASS_7.3-60           WGCNA_1.72-1         
## [16] fastcluster_1.2.3     dynamicTreeCut_1.63-1 scales_1.2.1         
## [19] ggraph_2.1.0          tidygraph_1.2.3       umap_0.2.10.0        
## [22] clusterProfiler_4.8.2 SeuratObject_4.1.3    Seurat_4.3.0.1       
## [25] ggalluvial_0.12.5     ggrepel_0.9.3         correlation_0.8.4    
## [28] ggpubr_0.6.0          igraph_1.5.0.1        broom_1.0.5          
## [31] circlize_0.4.15       ComplexHeatmap_2.16.0 RColorBrewer_1.1-3   
## [34] viridis_0.6.4         viridisLite_0.4.2     gridExtra_2.3        
## [37] patchwork_1.1.2       Matrix_1.6-0          DT_0.28              
## [40] readxl_1.4.3          lubridate_1.9.2       forcats_1.0.0        
## [43] stringr_1.5.0         dplyr_1.1.2           purrr_1.0.1          
## [46] readr_2.1.4           tidyr_1.3.0           tibble_3.2.1         
## [49] ggplot2_3.4.2         tidyverse_2.0.0      
## 
## loaded via a namespace (and not attached):
##   [1] graph_1.78.0                ica_1.0-3                  
##   [3] plotly_4.10.2               Formula_1.2-5              
##   [5] zlibbioc_1.46.0             tidyselect_1.2.0           
##   [7] bit_4.0.5                   doParallel_1.0.17          
##   [9] clue_0.3-64                 rjson_0.2.21               
##  [11] blob_1.2.4                  broom.helpers_1.13.0       
##  [13] S4Arrays_1.0.5              pbkrtest_0.5.2             
##  [15] parallel_4.3.2              Biobase_2.60.0             
##  [17] png_0.1-8                   cli_3.6.3                  
##  [19] ggplotify_0.1.1             bayestestR_0.13.1          
##  [21] askpass_1.1                 openssl_2.1.0              
##  [23] goftest_1.2-3               broom.mixed_0.2.9.4        
##  [25] uwot_0.1.16                 shadowtext_0.1.2           
##  [27] curl_5.0.1                  mime_0.12                  
##  [29] evaluate_0.21               tidytree_0.4.4             
##  [31] leiden_0.4.3                V8_4.3.3                   
##  [33] stringi_1.7.12              backports_1.4.1            
##  [35] XML_3.99-0.14               httpuv_1.6.11              
##  [37] AnnotationDbi_1.62.2        magrittr_2.0.3             
##  [39] splines_4.3.2               org.Hs.eg.db_3.17.0        
##  [41] sctransform_0.3.5           ggbeeswarm_0.7.2           
##  [43] DBI_1.1.3                   ggExtra_0.10.1             
##  [45] HDF5Array_1.28.1            jquerylib_0.1.4            
##  [47] withr_2.5.0                 corpcor_1.6.10             
##  [49] enrichplot_1.20.0           lmtest_0.9-40              
##  [51] GSEABase_1.62.0             htmlwidgets_1.6.2          
##  [53] S4Vectors_0.38.1            SingleCellExperiment_1.22.0
##  [55] ggvenn_0.1.10               labeling_0.4.2             
##  [57] cellranger_1.1.0            MatrixGenerics_1.12.3      
##  [59] annotate_1.78.0             reticulate_1.30            
##  [61] zoo_1.8-12                  XVector_0.40.0             
##  [63] knitr_1.43                  BiocGenerics_0.46.0        
##  [65] gt_0.9.0                    timechange_0.2.0           
##  [67] foreach_1.5.2               fansi_1.0.4                
##  [69] data.table_1.14.8           ggtree_3.8.0               
##  [71] rhdf5_2.44.0                RSpectra_0.16-1            
##  [73] irlba_2.3.5.1               ggrastr_1.0.2              
##  [75] gridGraphics_0.5-1          commonmark_1.9.0           
##  [77] ellipsis_0.3.2              lazyeval_0.2.2             
##  [79] yaml_2.3.7                  survival_3.5-7             
##  [81] scattermore_1.2             crayon_1.5.2               
##  [83] RcppAnnoy_0.0.21            progressr_0.13.0           
##  [85] tweenr_2.0.2                later_1.3.1                
##  [87] Rgraphviz_2.44.0            ggridges_0.5.4             
##  [89] codetools_0.2-19            base64enc_0.1-3            
##  [91] GlobalOptions_0.1.2         KEGGREST_1.40.0            
##  [93] ggfittext_0.10.1            Rtsne_0.16                 
##  [95] shape_1.4.6                 estimability_1.4.1         
##  [97] foreign_0.8-85              pkgconfig_2.0.3            
##  [99] KEGGgraph_1.60.0            xml2_1.3.5                 
## [101] GenomicRanges_1.52.0        IRanges_2.34.1             
## [103] aplot_0.1.10                spatstat.sparse_3.0-2      
## [105] ape_5.7-1                   xtable_1.8-4               
## [107] car_3.1-2                   highr_0.10                 
## [109] plyr_1.8.8                  polylabelr_0.2.0           
## [111] httr_1.4.6                  tools_4.3.2                
## [113] globals_0.16.2              beeswarm_0.4.0             
## [115] htmlTable_2.4.1             checkmate_2.2.0            
## [117] nlme_3.1-163                HDO.db_0.99.1              
## [119] digest_0.6.33               numDeriv_2016.8-1.1        
## [121] furrr_0.3.1                 farver_2.1.1               
## [123] tzdb_0.4.0                  reshape2_1.4.4             
## [125] yulab.utils_0.0.6           rpart_4.1.21               
## [127] glue_1.6.2                  cachem_1.0.8               
## [129] polyclip_1.10-4             Hmisc_5.1-0                
## [131] generics_0.1.3              Biostrings_2.68.1          
## [133] stats4_4.3.2                mvtnorm_1.2-2              
## [135] parallelly_1.36.0           impute_1.74.1              
## [137] ScaledMatrix_1.8.1          carData_3.0-5              
## [139] minqa_1.2.5                 pbapply_1.7-2              
## [141] randomcoloR_1.1.0.1         SummarizedExperiment_1.30.2
## [143] vroom_1.6.3                 gson_0.1.0                 
## [145] utf8_1.2.3                  graphlayouts_1.0.0         
## [147] datawizard_0.8.0            preprocessCore_1.62.1      
## [149] ggsignif_0.6.4              shiny_1.7.4.1              
## [151] GenomeInfoDbData_1.2.10     rhdf5filters_1.12.1        
## [153] parameters_0.21.1           RCurl_1.98-1.12            
## [155] memoise_2.0.1               rmarkdown_2.23             
## [157] downloader_0.4              future_1.33.0              
## [159] RANN_2.6.1                  Cairo_1.6-1                
## [161] spatstat.data_3.0-1         rstudioapi_0.15.0          
## [163] cluster_2.1.4               janitor_2.2.0              
## [165] spatstat.utils_3.0-3        hms_1.1.3                  
## [167] fitdistrplus_1.1-11         munsell_0.5.0              
## [169] cowplot_1.1.1               colorspace_2.1-0           
## [171] ellipse_0.5.0               rlang_1.1.1                
## [173] GenomeInfoDb_1.36.1         DelayedMatrixStats_1.22.6  
## [175] sparseMatrixStats_1.12.2    ggforce_0.4.1              
## [177] mgcv_1.9-0                  xfun_0.39                  
## [179] coda_0.19-4                 iterators_1.0.14           
## [181] matrixStats_1.0.0           rARPACK_0.11-0             
## [183] abind_1.4-5                 GOSemSim_2.26.1            
## [185] treeio_1.25.2               Rhdf5lib_1.22.1            
## [187] bitops_1.0-7                promises_1.2.0.1           
## [189] scatterpie_0.2.1            RSQLite_2.3.1              
## [191] qvalue_2.32.0               fgsea_1.26.0               
## [193] DelayedArray_0.26.7         GO.db_3.17.0               
## [195] compiler_4.3.2              beachmat_2.16.0            
## [197] boot_1.3-28.1               listenv_0.9.0              
## [199] Rcpp_1.0.11                 BiocSingular_1.16.0        
## [201] tensor_1.5                  BiocParallel_1.34.2        
## [203] insight_0.19.3              gridtext_0.1.5             
## [205] spatstat.random_3.1-5       R6_2.5.1                   
## [207] fastmap_1.1.1               fastmatch_1.1-3            
## [209] rstatix_0.7.2               vipor_0.4.5                
## [211] ROCR_1.0-11                 rsvd_1.0.5                 
## [213] nnet_7.3-19                 gtable_0.3.3               
## [215] KernSmooth_2.23-22          miniUI_0.1.1.1             
## [217] deldir_1.0-9                htmltools_0.5.5            
## [219] bit64_4.0.5                 spatstat.explore_3.2-1     
## [221] lifecycle_1.0.3             nloptr_2.0.3               
## [223] sass_0.4.7                  vctrs_0.6.3                
## [225] spatstat.geom_3.2-4         snakecase_0.11.0           
## [227] DOSE_3.26.1                 ggfun_0.1.1                
## [229] sp_2.0-0                    future.apply_1.11.0        
## [231] bslib_0.5.0                 pillar_1.9.0               
## [233] magick_2.8.1                jsonlite_1.8.7             
## [235] markdown_1.7                GetoptLong_1.0.5

Figure Panels

source_rmd <- function(rmd_file){
  knitr::knit(rmd_file, output = tempfile())
}

source_rmd("Make_my_figurepanels.Rmd")

## make one Pdf
library(qpdf)
qpdf::pdf_combine(
  input = c("../Manuscript/Figure_1.pdf", 
            "../Manuscript/Figure_2.pdf",
            "../Manuscript/Figure_3.pdf", 
            "../Manuscript/Figure_4.pdf", 
            "../Manuscript/Figure_5.pdf", 
            "../Manuscript/Figure_6.pdf",
            "../Manuscript/Figure_7.pdf"),
  output = "../Manuscript/Lautenbach_etal_mainfigures.pdf"
)

qpdf::pdf_combine(
  input = c("../Manuscript/Figure_1_S1.pdf", 
            "../Manuscript/Figure_1_S2.pdf", 
            "../Manuscript/Figure_1_S3.pdf", 
            
            "../Manuscript/Figure_2_S4.pdf",
            "../Manuscript/Figure_2_S5.pdf", 
            
            "../Manuscript/Figure_3_S6.pdf", 
            "../Manuscript/Figure_3_S7.pdf", 
            
            "../Manuscript/Figure_4_S8.pdf",
            
            "../Manuscript/Figure_5_S9.pdf"
            ),
  output = "../Manuscript/Lautenbach_etal_supplementaryfigures.pdf"
)
sessionInfo()
## R version 4.3.2 (2023-10-31)
## Platform: aarch64-apple-darwin20 (64-bit)
## Running under: macOS Sonoma 14.7.4
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: Europe/Stockholm
## tzcode source: internal
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] gridBase_0.4-7        GSVA_1.48.3           UpSetR_1.4.0         
##  [4] see_0.8.0             pathview_1.40.0       ggtext_0.1.2         
##  [7] gtsummary_1.7.2       emmeans_1.8.7         lmerTest_3.1-3       
## [10] lme4_1.1-34           eulerr_7.0.2          mixOmics_6.24.0      
## [13] lattice_0.21-8        MASS_7.3-60           WGCNA_1.72-1         
## [16] fastcluster_1.2.3     dynamicTreeCut_1.63-1 scales_1.2.1         
## [19] ggraph_2.1.0          tidygraph_1.2.3       umap_0.2.10.0        
## [22] clusterProfiler_4.8.2 SeuratObject_4.1.3    Seurat_4.3.0.1       
## [25] ggalluvial_0.12.5     ggrepel_0.9.3         correlation_0.8.4    
## [28] ggpubr_0.6.0          igraph_1.5.0.1        broom_1.0.5          
## [31] circlize_0.4.15       ComplexHeatmap_2.16.0 RColorBrewer_1.1-3   
## [34] viridis_0.6.4         viridisLite_0.4.2     gridExtra_2.3        
## [37] patchwork_1.1.2       Matrix_1.6-0          DT_0.28              
## [40] readxl_1.4.3          lubridate_1.9.2       forcats_1.0.0        
## [43] stringr_1.5.0         dplyr_1.1.2           purrr_1.0.1          
## [46] readr_2.1.4           tidyr_1.3.0           tibble_3.2.1         
## [49] ggplot2_3.4.2         tidyverse_2.0.0      
## 
## loaded via a namespace (and not attached):
##   [1] graph_1.78.0                ica_1.0-3                  
##   [3] plotly_4.10.2               Formula_1.2-5              
##   [5] zlibbioc_1.46.0             tidyselect_1.2.0           
##   [7] bit_4.0.5                   doParallel_1.0.17          
##   [9] clue_0.3-64                 rjson_0.2.21               
##  [11] blob_1.2.4                  broom.helpers_1.13.0       
##  [13] S4Arrays_1.0.5              pbkrtest_0.5.2             
##  [15] parallel_4.3.2              Biobase_2.60.0             
##  [17] png_0.1-8                   cli_3.6.3                  
##  [19] ggplotify_0.1.1             bayestestR_0.13.1          
##  [21] askpass_1.1                 openssl_2.1.0              
##  [23] goftest_1.2-3               broom.mixed_0.2.9.4        
##  [25] uwot_0.1.16                 shadowtext_0.1.2           
##  [27] curl_5.0.1                  mime_0.12                  
##  [29] evaluate_0.21               tidytree_0.4.4             
##  [31] leiden_0.4.3                V8_4.3.3                   
##  [33] stringi_1.7.12              backports_1.4.1            
##  [35] XML_3.99-0.14               httpuv_1.6.11              
##  [37] AnnotationDbi_1.62.2        magrittr_2.0.3             
##  [39] splines_4.3.2               org.Hs.eg.db_3.17.0        
##  [41] sctransform_0.3.5           ggbeeswarm_0.7.2           
##  [43] DBI_1.1.3                   ggExtra_0.10.1             
##  [45] HDF5Array_1.28.1            jquerylib_0.1.4            
##  [47] withr_2.5.0                 corpcor_1.6.10             
##  [49] enrichplot_1.20.0           lmtest_0.9-40              
##  [51] GSEABase_1.62.0             htmlwidgets_1.6.2          
##  [53] S4Vectors_0.38.1            SingleCellExperiment_1.22.0
##  [55] ggvenn_0.1.10               labeling_0.4.2             
##  [57] cellranger_1.1.0            MatrixGenerics_1.12.3      
##  [59] annotate_1.78.0             reticulate_1.30            
##  [61] zoo_1.8-12                  XVector_0.40.0             
##  [63] knitr_1.43                  BiocGenerics_0.46.0        
##  [65] gt_0.9.0                    timechange_0.2.0           
##  [67] foreach_1.5.2               fansi_1.0.4                
##  [69] data.table_1.14.8           ggtree_3.8.0               
##  [71] rhdf5_2.44.0                RSpectra_0.16-1            
##  [73] irlba_2.3.5.1               ggrastr_1.0.2              
##  [75] gridGraphics_0.5-1          commonmark_1.9.0           
##  [77] ellipsis_0.3.2              lazyeval_0.2.2             
##  [79] yaml_2.3.7                  survival_3.5-7             
##  [81] scattermore_1.2             crayon_1.5.2               
##  [83] RcppAnnoy_0.0.21            progressr_0.13.0           
##  [85] tweenr_2.0.2                later_1.3.1                
##  [87] Rgraphviz_2.44.0            ggridges_0.5.4             
##  [89] codetools_0.2-19            base64enc_0.1-3            
##  [91] GlobalOptions_0.1.2         KEGGREST_1.40.0            
##  [93] ggfittext_0.10.1            Rtsne_0.16                 
##  [95] shape_1.4.6                 estimability_1.4.1         
##  [97] foreign_0.8-85              pkgconfig_2.0.3            
##  [99] KEGGgraph_1.60.0            xml2_1.3.5                 
## [101] GenomicRanges_1.52.0        IRanges_2.34.1             
## [103] aplot_0.1.10                spatstat.sparse_3.0-2      
## [105] ape_5.7-1                   xtable_1.8-4               
## [107] car_3.1-2                   highr_0.10                 
## [109] plyr_1.8.8                  polylabelr_0.2.0           
## [111] httr_1.4.6                  tools_4.3.2                
## [113] globals_0.16.2              beeswarm_0.4.0             
## [115] htmlTable_2.4.1             checkmate_2.2.0            
## [117] nlme_3.1-163                HDO.db_0.99.1              
## [119] digest_0.6.33               numDeriv_2016.8-1.1        
## [121] furrr_0.3.1                 farver_2.1.1               
## [123] tzdb_0.4.0                  reshape2_1.4.4             
## [125] yulab.utils_0.0.6           rpart_4.1.21               
## [127] glue_1.6.2                  cachem_1.0.8               
## [129] polyclip_1.10-4             Hmisc_5.1-0                
## [131] generics_0.1.3              Biostrings_2.68.1          
## [133] stats4_4.3.2                mvtnorm_1.2-2              
## [135] parallelly_1.36.0           impute_1.74.1              
## [137] ScaledMatrix_1.8.1          carData_3.0-5              
## [139] minqa_1.2.5                 pbapply_1.7-2              
## [141] randomcoloR_1.1.0.1         SummarizedExperiment_1.30.2
## [143] vroom_1.6.3                 gson_0.1.0                 
## [145] utf8_1.2.3                  graphlayouts_1.0.0         
## [147] datawizard_0.8.0            preprocessCore_1.62.1      
## [149] ggsignif_0.6.4              shiny_1.7.4.1              
## [151] GenomeInfoDbData_1.2.10     rhdf5filters_1.12.1        
## [153] parameters_0.21.1           RCurl_1.98-1.12            
## [155] memoise_2.0.1               rmarkdown_2.23             
## [157] downloader_0.4              future_1.33.0              
## [159] RANN_2.6.1                  Cairo_1.6-1                
## [161] spatstat.data_3.0-1         rstudioapi_0.15.0          
## [163] cluster_2.1.4               janitor_2.2.0              
## [165] spatstat.utils_3.0-3        hms_1.1.3                  
## [167] fitdistrplus_1.1-11         munsell_0.5.0              
## [169] cowplot_1.1.1               colorspace_2.1-0           
## [171] ellipse_0.5.0               rlang_1.1.1                
## [173] GenomeInfoDb_1.36.1         DelayedMatrixStats_1.22.6  
## [175] sparseMatrixStats_1.12.2    ggforce_0.4.1              
## [177] mgcv_1.9-0                  xfun_0.39                  
## [179] coda_0.19-4                 iterators_1.0.14           
## [181] matrixStats_1.0.0           rARPACK_0.11-0             
## [183] abind_1.4-5                 GOSemSim_2.26.1            
## [185] treeio_1.25.2               Rhdf5lib_1.22.1            
## [187] bitops_1.0-7                promises_1.2.0.1           
## [189] scatterpie_0.2.1            RSQLite_2.3.1              
## [191] qvalue_2.32.0               fgsea_1.26.0               
## [193] DelayedArray_0.26.7         GO.db_3.17.0               
## [195] compiler_4.3.2              beachmat_2.16.0            
## [197] boot_1.3-28.1               listenv_0.9.0              
## [199] Rcpp_1.0.11                 BiocSingular_1.16.0        
## [201] tensor_1.5                  BiocParallel_1.34.2        
## [203] insight_0.19.3              gridtext_0.1.5             
## [205] spatstat.random_3.1-5       R6_2.5.1                   
## [207] fastmap_1.1.1               fastmatch_1.1-3            
## [209] rstatix_0.7.2               vipor_0.4.5                
## [211] ROCR_1.0-11                 rsvd_1.0.5                 
## [213] nnet_7.3-19                 gtable_0.3.3               
## [215] KernSmooth_2.23-22          miniUI_0.1.1.1             
## [217] deldir_1.0-9                htmltools_0.5.5            
## [219] bit64_4.0.5                 spatstat.explore_3.2-1     
## [221] lifecycle_1.0.3             nloptr_2.0.3               
## [223] sass_0.4.7                  vctrs_0.6.3                
## [225] spatstat.geom_3.2-4         snakecase_0.11.0           
## [227] DOSE_3.26.1                 ggfun_0.1.1                
## [229] sp_2.0-0                    future.apply_1.11.0        
## [231] bslib_0.5.0                 pillar_1.9.0               
## [233] magick_2.8.1                jsonlite_1.8.7             
## [235] markdown_1.7                GetoptLong_1.0.5
LS0tCnRpdGxlOiAiSW50ZWdyYXRlZCBwcm90ZW9taWNzIGFuZCBzaW5nbGUtY2VsbCB0cmFuc2NyaXB0b21pY3MgcmV2ZWFsIGltbXVuZSBkeW5hbWljcyBhbmQgc2V2ZXJpdHkgbWFya2VycyBpbiBhY3V0ZSBQbGFzbW9kaXVtIGZhbGNpcGFydW0gbWFsYXJpYSIKYXV0aG9yOiAiTWF4aW1pbGlhbiBKdWxpdXMgTGF1dGVuYmFjaCIKZGF0ZTogJzIwMjQtMDMtMDUnCm91dHB1dDoKICAgaHRtbF9kb2N1bWVudDoKICAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIgogICAgIHRvYzogdHJ1ZQogICAgIGRlcHRoOiAyCiAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgIGdpdGh1Yl9kb2N1bWVudDoKICAgICAgIHByZXZpZXdfaHRtbDogZmFsc2UKICAgICAgIAogICAgICAgYWJzdHJhY3Q6IFRoaXMgbWFya2Rvd24gY29udGFpbnMgYWxsIGNvZGUgcmVsYXRlZCB0byBkb3duc3RyZWFtIGFuYWx5c2lzIGFuZCBmaWd1cmVzIG9mIHRoZSBtYW51c2NyaXB0LgotLS0KCiMgU2V0IHVwCmBgYHtyIHNldHVwLWNodW5rLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSkKYGBgCgoqKkxvYWQgbGlicmFyaWVzKioKCmBgYHtyIGxpYnJhcmllcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KGNpcmNsaXplKQpsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KGJyb29tKQojbGlicmFyeShicm9vbS5taXhlZCkKbGlicmFyeShpZ3JhcGgpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGNvcnJlbGF0aW9uKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoZ2dhbGx1dmlhbCkKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQpsaWJyYXJ5KHVtYXApICMjIGh0dHBzOi8vZ2l0aHViLmNvbS90a29ub3BrYS91bWFwL2Jsb2IvbWFzdGVyL3ZpZ25ldHRlcy91bWFwLlJtZApsaWJyYXJ5KHRpZHlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KFdHQ05BKQpsaWJyYXJ5KG1peE9taWNzKQpsaWJyYXJ5KGV1bGVycikKbGlicmFyeShsbWVyVGVzdCkKI2xpYnJhcnkoYnJvb20ubWl4ZWQpCmxpYnJhcnkoZW1tZWFucykKYGBgCgoqKkxvYWQgZGF0YSoqCgpgYGB7ciBsb2FkLWRhdGEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgTWFsYXJpYSBFeHBsb3JlIDE1MzYgZGF0YQpkYXRhIDwtIHV0aWxzOjpyZWFkLmRlbGltKCIuLi9kYXRhL2RhdGEvZXhwbG9yZTE1MzYvMjAyMzA0MTFfaW5mZWN0aW91c19vbGluay50c3YiKSAKIyBNYWxhcmlhIHNhbXBsZVRhYmxlCnNhbXBsZVRhYmxlX3NpbXBsZSA8LSByZWFkUkRTKCIuLi9kYXRhL21ldGFEYXRhX2NsZWFuL0V4cGxvcmUxNTM2X01hbGFyaWFfc2FtcGxlVGFibGVfc2ltcGxlLnJkcyIpCiMgTWFsYXJpYSBzdWJqZWN0VGFibGUKc3ViamVjdFRhYmxlIDwtIHJlYWRSRFMoIi4uL2RhdGEvbWV0YURhdGFfY2xlYW4vTWFsYXJpYVJlc291cmNlX3N1YmplY3RUYWJsZS5yZHMiKQojIE1hbGFyaWEgY2xpbmNoZW0gZGF0YQpjbGluY2hlbV9zdHVkeV9wYXRzX2FjdXRlLndpZGUgPC0gcmVhZFJEUygiLi4vZGF0YS9tZXRhRGF0YV9jbGVhbi9FeHBsb3JlMTUzNl9DbGluaWNhbENoZW1pc3RyeV9hY3V0ZS5yZHMiKQoKIyBUcm9waWNhbCBmZXZlciBFeHBsb3JlIDE1MzYgZGF0YQpURi5sb25nIDwtIHJlYWRSRFMoIi4uL2RhdGEvZGF0YV9jbGVhbi9FeHBsb3JlMTUzNl9URl90aWR5X2xvbmcucmRzIikKIyBUcm9waWNhbCBmZXZlciBzYW1wbGVUYWJsZQpURl9zYW1wbGVUYWJsZSA8LSByZWFkUkRTKCIuLi9kYXRhL21ldGFEYXRhX2NsZWFuL0V4cGxvcmUxNTM2X1RGX3NhbXBsZVRhYmxlLnJkcyIpCgoKIyBIUEEgdjI0CmhwYV8yNC4wIDwtIHJlYWRfdHN2KCIuLi9kYXRhL2hwYS9wcm90ZWluYXRsYXNfdjI0LnRzdiIpICU+JSBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JSAKICBtdXRhdGUoc2VjcmV0b21lX2xvY2F0aW9uID0gaWZlbHNlKGlzLm5hKHNlY3JldG9tZV9sb2NhdGlvbiksIk5vdCBzZWNyZXRlZCIsc2VjcmV0b21lX2xvY2F0aW9uKSkKIyBIUEEgdGlzc3VlIGV4cHJlc3Npb24gdjIzCmhwYS50aXNzdWUgPC0gcmVhZF90c3YoIi4uL2RhdGEvaHBhL3JuYV90aXNzdWVfY29uc2Vuc3VzLnRzdiIpICU+JSBqYW5pdG9yOjpjbGVhbl9uYW1lcygpCgoKIyBMb2FkIGNsZWFuZWQgbWFsYXJpYSBkYXRhCiMtICAgYXNzYXlzIHdpdGggUUMgd2FybiBpbiBtb3JlIHRoYW4gNzAlIG9mIGFsbCBhc3NheXMKIy0gICBzYW1wbGVzIHdpdGggbW9yZSB0aGFuIDcwJSBiZWxvdyBMT0QKZGF0YS53aWRlIDwtIHJlYWRSRFMoIi4uL2RhdGEvZGF0YV9jbGVhbi9FeHBsb3JlMTUzNl90aWR5X3dpZGUucmRzIikKZGF0YS5sb25nIDwtIHJlYWRSRFMoIi4uL2RhdGEvZGF0YV9jbGVhbi9FeHBsb3JlMTUzNl90aWR5X2xvbmcucmRzIikKCiMjIEV4cGxvcmUgMTUzNiBkYXRhIHNldCAtIE1HSCBDb3ZpZC0xOSBzdHVkeSwgRmlsYmluIGV0IGFsLiAyMDIxCmNvdmlkX05QWGRhdGEgPC0gcmVhZF9kZWxpbSgiLi4vZGF0YS9NR0hfT0xJTktfQ09WSUQvTUdIX0NPVklEX09MSU5LX05QWC50eHQiLGNvbW1lbnQgPSAiIyMiKQptZ2guY292aWQubWV0YSA8LSByZWFkX2RlbGltKCIuLi9kYXRhL01HSF9PTElOS19DT1ZJRC9NR0hfQ09WSURfQ2xpbmljYWxfSW5mby50eHQiLCBjb21tZW50PSIjIyIpICU+JSBqYW5pdG9yOjpjbGVhbl9uYW1lcygpCm1naC5jb3ZpZC5tZXRhLmtleSA8LSByZWFkX2V4Y2VsKCIuLi9kYXRhL01HSF9PTElOS19DT1ZJRC92YXJpYWJsZV9kZXNjcmlwdGlvbnMueGxzeCIpCgojIyBsb2FkIHRyb3BpY2FsIGZldmVyIGNvaG9ydCBkYXRhClRGX1NPRkEgPC0gcmVhZFJEUygiLi4vZGF0YS9tZXRhRGF0YV9jbGVhbi8yMDIxMjEzX1RGX0RBX1RST1BfU09GQXNjb3Jlcy5yZHMiKSAlPiUgZmlsdGVyKGRpYWdub3NlX2NsZWFuIT0iUC5mYWxjaXBhcnVtIikKVEYubG9uZyA8LSByZWFkUkRTKCIuLi9kYXRhL2RhdGFfY2xlYW4vRXhwbG9yZTE1MzZfVEZfdGlkeV9sb25nLnJkcyIpCgojIyBsb2RpbmcgIE1JUCBDb2hvcnQgRkFDUyBkYXRhIC0gTGF1dGVuYmFjaCBldCBhbC4gQ2VsbCBSZXBvcnRzIDIwMjIKCkZBQ3NfZGF0YSA8LSByZWFkX2RlbGltKCIuLi8uLi9NYWxhcmlhVHJhdmVsbGVycy9kYXRhL1RyYXZlbGxlckNvaG9ydF9GQUNTX2xvZzJjcHVfbG9uZy5jc3YiKQpGQUNTX21ldGEgPC0gcmVhZF9kZWxpbSgiLi4vLi4vTWFsYXJpYVRyYXZlbGxlcnMvZGF0YS9UcmF2ZWxsZXJDb2hvcnRfU3ViamVjdFRhYmxlLmNzdiIpCgpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CnJlc3VsdC5kaXIgPC0gIi4uL01hbnVzY3JpcHQvIgpyZXN1bHQudG1wLmRpciA8LSAiLi4vTWFudXNjcmlwdC90bXAvIgppZmVsc2UoaXNGQUxTRShkaXIuZXhpc3RzKHJlc3VsdC50bXAuZGlyKSksIAogICAgICAgZGlyLmNyZWF0ZShyZXN1bHQudG1wLmRpcixyZWN1cnNpdmUgPSBUUlVFKSxOQSkKYGBgCgoqKlNldCB0aGVtZSAmIGNvbG9ycyoqCgpgYGB7cn0KdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gNikpCgp0aW1lM19jb2wgPC0gYygiQWN1dGUiID0gIiNDNTFCN0QiLCAKICAgICAgICAgICAgICAgIkQxMCIgPSAiI0U5QTNDOSIsCiAgICAgICAgICAgICAgICJNMTIiID0gIiM0RDkyMjEiKQoKc2V4Ml9jb2wgPC0gYyhtYWxlID0gIiNjNWI4ZGMiLAogICAgICAgICAgICAgIGZlbWFsZSA9ICIjYjlkMmIxIikKCmVuZGVtaWMyX2NvbCA8LSBjKHByaW1hcnlfaW5mZWN0ZWQgPSAiIzk5OEVDMyIsCiAgICAgICAgICAgICAgICAgIHByZXZpb3VzbHlfZXhwb3NlZCA9ICIjRjFBMzQwIikKc2V2ZXJlXzVfY29sID0gYygiMSI9InRvbWF0byIsCiAgICAgICAgICAgICAgICAgIjAiPSJncmV5ODAiKQoKc2VjcmV0b21lX2xvY2F0aW9uX2NvbHMgPC0gYygiU2VjcmV0ZWQgdG8gYmxvb2QiID0gIiNGQjgwNzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbnRyYWNlbGx1bGFyIGFuZCBtZW1icmFuZSIgPSAiIzhERDNDNyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIG90aGVyIHRpc3N1ZXMiID0gIiNCM0RFNjkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCB0byBleHRyYWNlbGx1bGFyIG1hdHJpeCIgPSAiIzgwQjFEMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIGJyYWluIiA9ICIjYjlkMmIxIiwjIiNGQ0NERTUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCB0byBkaWdlc3RpdmUgc3lzdGVtIiA9ICIjRkRCNDYyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgLSB1bmtub3duIGxvY2F0aW9uIiA9ICIjRkZGRjAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gbWFsZSByZXByb2R1Y3RpdmUgc3lzdGVtIiA9IHNleDJfY29sW1sxXV0sIyIjQkVCQURBIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gZmVtYWxlIHJlcHJvZHVjdGl2ZSBzeXN0ZW0iID0gc2V4Ml9jb2xbWzJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm90IHNlY3JldGVkIiA9ICIjRDlEOUQ5IikKCnNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlY19jb2xzIDwtIGMoc2VjcmV0b21lX2xvY2F0aW9uX2NvbHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiTm90IHNlY3JldGVkIC0gVGlzc3VlIGVucmljaGVkIiA9ICIjODg0MTlkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBUaXNzdWUgZW5oYW5jZWQiID0gIiM4Yzk2YzYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdCBzZWNyZXRlZCAtIEdyb3VwIGVucmljaGVkIiA9ICIjYjNjZGUzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBMb3cgdGlzc3VlIHNwZWNpZmljaXR5IiA9ICIjZWRmOGZiIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpTT0ZBX3N1Yl9jb2wgPSBjb2xvclJhbXAyKGMoMCw0KSwgYygid2hpdGUiLCJyZWQiKSkKCnBhdGllbnRfa2NsdXN0MyA8LSBjKCczJyA9ICIjOTJjNWRlIiwgJzInID0gIiNmNGE1ODIiLCAnMScgPSAiI2NhMDAyMCIpCnBhdGllbnRfa2NsdXN0M19sYWIgPC0gYygibWlsZCI9IiM5MmM1ZGUiLCAibW9kZXJhdGUiPSIjZjRhNTgyIiwgInNldmVyZSI9IiNjYTAwMjAiKQpwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYgPC0gYygibWlsZCI9IiM5MmM1ZGUiLCAibW9kZXJhdGUiPSIjZjRhNTgyIiwgInNldmVyZSI9IiNjYTAwMjAiLCJjb252YWxlc2NlbmNlIiA9ImdyZXk1MCIpCgoKClNPRkFfc3ViX2NvbCA9IGNvbG9yUmFtcDIoYygwLDQpLCBjKCJ3aGl0ZSIsInJlZCIpKQoKU09GQV90b3RhbF9jb2wgPSBjb2xvclJhbXAyKGMobWluKHN1YmplY3RUYWJsZSRTT0ZBX3RvdGFsLG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhbihzdWJqZWN0VGFibGUkU09GQV90b3RhbCxuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoc3ViamVjdFRhYmxlJFNPRkFfdG90YWwsbmEucm0gPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKGJyZXdlci5wYWwoMyxuYW1lPSJQdUJ1IikpKQoKIyMgZGltZW5zaW5hbGl0eSByZWR1Y3Rpb24gdGhlbWUKbXlfZGltcmVkX3RoZW1lIDwtIHRoZW1lX2NsYXNzaWMoKSArIAogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICN0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgI2xlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgCgojIyBhNCBwZGYgdGhlbWUKdGhlbWVfYTRfcGRmIDwtIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICMjIGxlZ2VuZAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgxLCAnY20nKSwgI2NoYW5nZSBsZWdlbmQga2V5IHNpemUKICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjI1LCAnY20nKSwgI2NoYW5nZSBsZWdlbmQga2V5IGhlaWdodAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC4yNSwgJ2NtJyksICNjaGFuZ2UgbGVnZW5kIGtleSB3aWR0aAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksICNjaGFuZ2UgbGVnZW5kIHRpdGxlIGZvbnQgc2l6ZQogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICMjIGxhYmVsCiAgICAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICBwbG90LmNhcHRpb24gPSAgZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgIyMgZmFjZXRfZ3JpZAogICAgICAgICAgICAgICAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LGZhY2U9ImJvbGQiKSwKICAgICAgICAgICAgICAgICAgICAgICNzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiCikKCiMjIHBhdGNod29yayBwYW5lbCBhNCBwZGYgdGhlbWUKcGF0Y2h3b3JrX3BhbmVsX2E0X3BkZiA8LSBwYXRjaHdvcms6OnBsb3RfYW5ub3RhdGlvbih0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGFnID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNixmYWNlID0gJ2JvbGQnKQopLAp0YWdfbGV2ZWxzID0gJ0EnKSAKYGBgCgpgYGB7ciBleHRyYS1zYW1wbGUtaW5mb30KYXN5bV9zdHVkeV9pZCA8LSBjKCIyMDIxMDA0IikKCiMjIDIwMTMwMDQgLSBMaWIgMQojIyAyMDEzMDA3IC0gTGliIDIKIyMgMjAxMzAwOCAtIExpYiAzCiMjIDIwMTgwMDIgLSBMaWIgNAoKcmhhcHNvZHlfc3R1ZHlfaWRzIDwtIGMoIjIwMTMwMDQiLCIyMDEzMDA3IiwiMjAxMzAwOCIsIjIwMTgwMDIiKQpgYGAKCgpgYGB7ciBtYXBwaW5nLXVuaXByb3QtZW5zZW1ibCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI3JlcXVpcmUoY2x1c3RlclByb2ZpbGVyKQoKI2xlbmd0aCh1bmlxdWUoZGF0YSRVbmlQcm90KSkgIyMgMTQ2MwptYXBwaW5nX3VuaXByb3RfZW5zZW1ibCA8LSBiaXRyKHVuaXF1ZShkYXRhJFVuaVByb3QpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tVHlwZT0iVU5JUFJPVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9UeXBlPWMoIlNZTUJPTCIsICJFTlNFTUJMIiwiRU5UUkVaSUQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT3JnRGI9Im9yZy5Icy5lZy5kYiIpICU+JSAKICBkcGx5cjo6cmVuYW1lKFVuaVByb3QgPSBVTklQUk9ULAogICAgICAgICAgICAgICAgU3ltYm9sID0gU1lNQk9MLAogICAgICAgICAgICAgICAgRW5zZW1ibCA9IEVOU0VNQkwsCiAgICAgICAgICAgICAgICBFbnRyZXogPSBFTlRSRVpJRCkgJT4lCiAgaW5uZXJfam9pbihkYXRhICU+JSBkcGx5cjo6c2VsZWN0KEFzc2F5LFVuaVByb3QpICU+JSBkcGx5cjo6ZGlzdGluY3QoKSxieT0iVW5pUHJvdCIpCgojd3JpdGVfZGVsaW0obWFwcGluZ191bmlwcm90X2Vuc2VtYmwsICIuLi8uLi8yMDIyX0V4cGxvcmUxNTM2RmFybmVydExhYi9kYXRhL01hcHBpbmdfRXhwbG9yZV9VbmlQcm90MkVuc2VtYmwudHh0IikKYGBgCgoKIyBGaWd1cmUgMSAKKipQbGFzbWEgcHJvdGVvbWljIHBlcnR1cmJhdGlvbiBkdXJpbmcgY2xpbmljYWwgbWFsYXJpYSoqCi0gQ29ob3J0IGNoYXJhY3RlcmlzdGljcwpgYGB7cn0KZmlnMS5saXN0IDwtIGxpc3QoKQpgYGAKCiMjIEZpZ3VyZSAxQgpgYGB7cn0KKGZpZzEubGlzdFtbImdlbmVyYWxfc2V4X2FnZV9kaXN0Il1dIDwtIHN1YmplY3RUYWJsZSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9YWdlLCBmaWxsPXNleCkpICsKICAgIGdlb21fZGVuc2l0eShhbHBoYT0uNikgKwogICAgI3RoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXNleDJfY29sKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXNleDJfY29sKSArCiAgICAKICAgIGxhYnMoZmlsbD0iU2V4IiwKICAgICAgICAgeD0iYWdlIFt5ZWFyc10iLAogICAgICAgICB5PSJkZW5zaXR5IikKKQpgYGAKCiMjIEZpZ3VyZSAxQwpgYGB7cn0KKGZpZzEubGlzdFtbInRpbWVwb2ludF9zZXhfcGVyYyJdXSA8LXNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgCiAgICBpbm5lcl9qb2luKHN1YmplY3RUYWJsZSxieT0ic3R1ZHlfaWQiKSAlPiUgCiAgICBncm91cF9ieShUaW1lLHNleCkgJT4lIAogICAgdGFsbHkoKSAlPiUgCiAgICBncm91cF9ieShUaW1lKSAlPiUgCiAgICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQ9bi9zdW0obikpICU+JSAKICAgIGdncGxvdChhZXMoeD1UaW1lLHk9bixmaWxsPXNleCkpICsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSJmaWxsIikgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZTAoc3ByaW50ZigiJTEuMWYiLCBwZXJjZW50KjEwMCksIiUiKSksCiAgICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZmlsbCh2anVzdD0wLjUpLCBjb2xvdXI9IndoaXRlIiwgc2l6ZSA9MS41KSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LGV4cGFuZCA9IGMoMCwuMDEpKSArIAogICAgI3RoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1zZXgyX2NvbCkgKwogICAgbGFicyhmaWxsPU5VTEwsCiAgICAgICAgIHg9TlVMTCwKICAgICAgICAgeT0iUGVyY2VudGFnZSIpCikKYGBgCgojIyBGaWd1cmUgMUQKCmBgYHtyfQooZmlnMS5saXN0W1sidGltZXBvaW50X2V4cG9zdXJlIl1dIDwtIHNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgCiAgICBpbm5lcl9qb2luKHN1YmplY3RUYWJsZSxieT0ic3R1ZHlfaWQiKSAlPiUgCiAgICBncm91cF9ieShUaW1lLGVuZGVtaWMpICU+JSAKICAgIHRhbGx5KCkgJT4lIAogICAgZ3JvdXBfYnkoVGltZSkgJT4lIAogICAgZHBseXI6Om11dGF0ZShwZXJjZW50PW4vc3VtKG4pKSAlPiUgCiAgbXV0YXRlKGVuZGVtaWMgPSBmYWN0b3IoZW5kZW1pYywgbGV2ZWxzPWMoInByaW1hcnlfaW5mZWN0ZWQiLCJwcmV2aW91c2x5X2V4cG9zZWQiKSkpICU+JSAKICAgIGdncGxvdChhZXMoeD1UaW1lLHk9bixmaWxsPWVuZGVtaWMpKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0iZmlsbCIpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUwKHNwcmludGYoIiUxLjFmIiwgcGVyY2VudCoxMDApLCIlIikpLAogICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2ZpbGwodmp1c3Q9MC41KSwgY29sb3VyPSJ3aGl0ZSIsIHNpemUgPTEuNSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCxleHBhbmQgPSBjKDAsLjAxKSkgKyAKICAgICN0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9ZW5kZW1pYzJfY29sLGxhYmVscz1jKCJwcmltYXJ5X2luZmVjdGVkIj0icHJpbWFyeSBpbmZlY3RlZCIsInByZXZpb3VzbHlfZXhwb3NlZCI9InByZXZpb3VzbHkgZXhwb3NlZCIpKSArCiAgICBsYWJzKGZpbGw9TlVMTCwKICAgICAgICAgeD1OVUxMLAogICAgICAgICB5PSJQZXJjZW50YWdlIikKKQpgYGAKCiMjIEZpZ3VyZSAxRQoKYGBge3J9CmRmIDwtIGRhdGEud2lkZSAlPiUgCiAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUgJT4lIAogICAgICAgICAgICAgICB0cmFuc211dGUoc2FtcGxlX2lkKSwKICAgICAgICAgICAgIGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGVfaWQiKQoKIyMgUEMgY2FsY3VsYXRpb24KcGNhUmVzIDwtIHN0YXRzOjpwcmNvbXAoZGYsY2VudGVyID0gVFJVRSwgc2NhbGUuID0gVFJVRSkKdmFyRXhwIDwtIHJvdW5kKHBjYVJlcyRzZGV2XjIgLyBzdW0ocGNhUmVzJHNkZXZeMikgKiAxMDApCnBjYURGIDwtIGRhdGEuZnJhbWUoUEMxID0gcGNhUmVzJHhbLCAxXSwKICAgICAgICAgICAgICAgICAgICBQQzIgPSBwY2FSZXMkeFssIDJdKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGVfaWQiKSAKCiMjIFByZXAgZm9yIHBsb3R0aW5nCmRhdGE0cGxvdCA8LSBwY2FERiAlPiUgCiAgZHBseXI6OmlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikKCgoocGNhX2ZpZzEgPC0gZGF0YTRwbG90ICU+JSAKICAgIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gVGltZSxmaWxsPU5VTEwsIGxhYmVsID0gTlVMTCkpICsKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjksIHNpemUgPSAxKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSB0aW1lM19jb2wpICsKICAgIGxhYnMoeCA9IHBhc3RlMCgiUEMxICgiLCAgdmFyRXhwWzFdLCAiICUpIiksCiAgICAgICAgIHkgPSBwYXN0ZTAoIlBDMiAoIiwgIHZhckV4cFsyXSwgIiAlKSIpKSArCiAgICB0aGVtZV9taW5pbWFsKCkgICsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksIAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSkKYGBgCgojIyBGaWd1cmUgMUYKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIG5lc3QgZGF0YQpkYXRhX25lc3RlZCA8LSBkYXRhLmxvbmcgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIAogIGdyb3VwX2J5KFVuaVByb3QsQXNzYXkpICU+JSAKICBuZXN0KCkKYGBgCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMjIG5lc3QgZGF0YQpkYXRhX25lc3RlZCA8LSBkYXRhLmxvbmcgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIAogIGxlZnRfam9pbihzdWJqZWN0VGFibGUgJT4lIHRyYW5zbXV0ZShzdHVkeV9pZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9zdXJlID0gZmFjdG9yKGVuZGVtaWMsIGxldmVscz1jKCJwcmltYXJ5X2luZmVjdGVkIiwicHJldmlvdXNseV9leHBvc2VkIikpKSwKICAgICAgICAgICAgYnk9InN0dWR5X2lkIikgJT4lIAogIGdyb3VwX2J5KFVuaVByb3QsQXNzYXkpICU+JSAKICBuZXN0KCkKCmxtZV9yZXMgPC0gZGF0YV9uZXN0ZWQgJT4lIAogIG11dGF0ZShsbWUucmVzLnNpbXBsZSA9IHB1cnJyOjptYXAoZGF0YSwgfiBsbWVyVGVzdDo6bG1lcihOUFggfiBUaW1lICsgZXhwb3N1cmUgKyAoMXxzdHVkeV9pZCksIFJFTUwgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbG1lNDo6bG1lckNvbnRyb2woY2hlY2suY29udi5zaW5ndWxhciA9ICJpZ25vcmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSAueCAlPiUgZHBseXI6OmZpbHRlcihUaW1lIT0iRDEwIikpKSwKICAgICAgICAgbG1lLnJlcy5jb21wbGV4ID0gcHVycnI6Om1hcChkYXRhLCB+IGxtZXJUZXN0OjpsbWVyKE5QWCB+IFRpbWUgKiBleHBvc3VyZSArICgxfHN0dWR5X2lkKSwgUkVNTCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbG1lNDo6bG1lckNvbnRyb2woY2hlY2suY29udi5zaW5ndWxhciA9ICJpZ25vcmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSAueCAlPiUgZHBseXI6OmZpbHRlcihUaW1lIT0iRDEwIikpKSwKICAgICAgICAgbG1lLnNpbXBsZS50aWR5ID0gcHVycnI6Om1hcChsbWUucmVzLnNpbXBsZSwgfiBicm9vbS5taXhlZDo6dGlkeSguLCkpLAogICAgICAgICBsbWUuY29tcGxleC50aWR5ID0gcHVycnI6Om1hcChsbWUucmVzLmNvbXBsZXgsIH4gYnJvb20ubWl4ZWQ6OnRpZHkoLikpLAoKICAgICAgICAgcG9zdGhvYy50aW1lID0gcHVycnI6Om1hcChsbWUucmVzLnNpbXBsZSwgfiBzdW1tYXJ5KGNvbnRyYXN0KGVtbWVhbnMoLiwgfiBUaW1lKSwgbWV0aG9kID0gInBhaXJ3aXNlIikpICU+JSB0aWJibGUoKSksCiAgICAgICAgIHBvc3Rob2MudGltZV9leHBvc3VyZSA9IHB1cnJyOjptYXAobG1lLnJlcy5jb21wbGV4LCB+IHN1bW1hcnkoY29udHJhc3QoZW1tZWFucyguLCB+IFRpbWUgKiBleHBvc3VyZSksIG1ldGhvZCA9ICJwYWlyd2lzZSIpKSAlPiUgdGliYmxlKCkpCiAgICAgICAgICkKYGBgCgoKLSBmaW5kaW5nIGJldHRlciBtb2RlbApgYGB7cn0KIyMgY29tcGFyZSBzaW1wbGUgKHdpdGhvdXQgaW50ZXJhY3Rpb24pIHdpdGggY29tcGxleCBtb2RlbCAoaW50ZXJhY3Rpb24pCmJpY19haWNfcmVzIDwtIGxtZV9yZXMgJT4lIAogIG11dGF0ZShzaW1wbGVfZ2xhbmNlID0gcHVycnI6Om1hcChsbWUucmVzLnNpbXBsZSwgfihicm9vbTo6Z2xhbmNlKC4pKSksCiAgICAgICAgIGNvbXBsZXhfZ2xhbmNlID0gcHVycnI6Om1hcChsbWUucmVzLmNvbXBsZXgsIH4oYnJvb206OmdsYW5jZSguKSkpKSAlPiUgCiAgdW5uZXN0KGNvbHMgPSBjKHNpbXBsZV9nbGFuY2UsY29tcGxleF9nbGFuY2UpLG5hbWVzX3NlcCA9ICIuIikgJT4lIAogIGRwbHlyOjpzZWxlY3QoQXNzYXksIGNvbnRhaW5zKCJBSUMiKSxjb250YWlucygiQklDIikpCgpkZl9iZXR0ZXJfbW9kZWwgPC0gYmljX2FpY19yZXMgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzPWMoLVVuaVByb3QsLUFzc2F5KSkgJT4lIAogIHNlcGFyYXRlKG5hbWUsIGludG89YygibW9kZWwiLCJldmFsIiksc2VwID0gIlxcLiIscmVtb3ZlID0gVCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBtb2RlbCwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgJT4lIAogIG11dGF0ZShzaW1wbGVfYmV0dGVyID0gc2ltcGxlX2dsYW5jZSA8IGNvbXBsZXhfZ2xhbmNlLAogICAgICAgICBzaW1wbGVfZGVsdGEgPSBzaW1wbGVfZ2xhbmNlLWNvbXBsZXhfZ2xhbmNlLAogICAgICAgICBiZXR0ZXJfbW9kZWwgPSBjYXNlX3doZW4oYWJzKHNpbXBsZV9kZWx0YSk+NiB+ICJjb21wbGV4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gInNpbXBsZSIpKQpgYGAKCmBgYHtyfQpkZl9iZXR0ZXJfbW9kZWwgJT4lIAogIGdyb3VwX2J5KGV2YWwpICU+JSAKICBjb3VudChiZXR0ZXJfbW9kZWwpICU+JSAKICBnZ3Bsb3QoYWVzKHg9YmV0dGVyX21vZGVsLCB5PW4pKSArCiAgZ2VvbV9jb2woKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9biksc2l6ZT0yLG51ZGdlX3kgPSA1MCkgKyAKICBmYWNldF93cmFwKH5ldmFsKQpgYGAKCgpgYGB7cn0KZGZfYmV0dGVyX21vZGVsICU+JSBmaWx0ZXIoZXZhbD09IkJJQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHRlcl9tb2RlbD09ImNvbXBsZXgiKSAKYGBgCgoKCgoKYGBge3J9CmxtZV9yZXNfcGFkaiA8LSBsbWVfcmVzICU+JSAKICB1bm5lc3QoY29scz0icG9zdGhvYy50aW1lIikgJT4lIAogIGZpbHRlcihjb250cmFzdD09IkFjdXRlIC0gTTEyIikgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKHAuYWRqID0gcC5hZGp1c3QocC52YWx1ZSwgbWV0aG9kPSJmZHIiKSwKICAgICAgICAgICAgICAgICAgRkRSID0gaWZlbHNlKHAuYWRqIDw9IDAuMDEsIFRSVUUsRkFMU0UpKSAlPiUgCiAgYXJyYW5nZShwLmFkaikKYGBgCgoKYGBge3J9CmFzc2F5X2JldHRlcl9jb21wbGV4X21vZGVsIDwtIGRmX2JldHRlcl9tb2RlbCAlPiUgZmlsdGVyKGV2YWw9PSJCSUMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZXR0ZXJfbW9kZWw9PSJjb21wbGV4IikgJT4lIHB1bGwoQXNzYXkpCgpwbG90KGV1bGVyKAogIGxpc3QoImFjdXRlX20xMiIgPSBsbWVfcmVzX3BhZGogJT4lIGZpbHRlcihGRFI9PVQpICU+JSBwdWxsKEFzc2F5KSwKICAgICAgICJiaWNfY29tcGxleF9iZXR0ZXIiID0gYXNzYXlfYmV0dGVyX2NvbXBsZXhfbW9kZWwpKSwjZGZfYmV0dGVyX21vZGVsICU+JSBmaWx0ZXIoZXZhbD09IkJJQyIsIGJldHRlcl9tb2RlbD09ImNvbXBsZXgiKSAlPiUgcHVsbChBc3NheSkpKSwKICAKICAgICAgICBmaWxscyA9IGMoIiNDNTFCN0QiLAogICAgICAgICAgICAgICAgICAid2hpdGUiKSwKICAgICAgIHF1YW50aXRpZXMgPSBUUlVFLAogICAgICAgbHR5ID0gMSwjMTozLAogICAgICAgZm9udHNpemU9MiwKICAgICAgIGxhYmVscyA9IGxpc3QoZm9udHNpemU9NyksCiAgICAgICBzaGFwZSA9ICJlbGxpcHNlIixhZGp1c3RfbGFiZWxzID0gVCkKYGBgCgpgYGB7cn0KbG1lX3Jlc19wYWRqICU+JSAKICB0cmFuc211dGUoQXNzYXksIGVzdGltYXRlLHAuYWRqKSAlPiUgCiAgZmlsdGVyKEFzc2F5ICVpbiUgYXNzYXlfYmV0dGVyX2NvbXBsZXhfbW9kZWwpICU+JSAKICBhcnJhbmdlKC1hYnMoZXN0aW1hdGUpKQpgYGAKCmBgYHtyfQpkYXAucmVzIDwtIGxtZV9yZXNfcGFkaiAlPiUgCiAgZHBseXI6OnJlbmFtZShsb2dGQyA9IGVzdGltYXRlKSAlPiUgCiAgbXV0YXRlKGRpcmVjdGlvbiA9IGlmZWxzZShsb2dGQzwwLCJkb3duIiwidXAiKSkgICU+JSAKICBkcGx5cjo6c2VsZWN0KC1jKGxtZS5yZXMuc2ltcGxlLGxtZS5yZXMuY29tcGxleCxsbWUuY29tcGxleC50aWR5KSkgJT4lIAogICMjIHJlbW92ZSBhc3NheXMgdGhhdCB3b3VsZCByZXF1aXJlIGEgY29tcGxleCBtb2RlbAogICBmaWx0ZXIoIUFzc2F5ICVpbiUgYXNzYXlfYmV0dGVyX2NvbXBsZXhfbW9kZWwpCmBgYAoKCmBgYHtyfQooZGFwLmFjdXRlLnZvbGNhbm8gPC0gZGFwLnJlcyAlPiUgCiAgIGdncGxvdChhZXMoeD1sb2dGQywgeT0tbG9nMTAocC5hZGopLCBjb2xvcj1GRFIpKSArCiAgIGdlb21fcG9pbnQoYWxwaGE9MC43LHNpemU9LjUsIHNoYXBlPTE2KSArCiAgIHRoZW1lX21pbmltYWwoKSArCiAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhID0gLiAlPiUgZmlsdGVyKEZEUiA9PVRSVUUsIGFicyhsb2dGQykgPjEuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBBc3NheSksIGNvbG9yPSJibGFjayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JjZSAgICAgICAgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gICAgPSAiYm90aCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LmFscGhhPS4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3gucGFkZGluZyA9IHVuaXQoMC4yLCAibGluZXMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gJ2dyZXk1MCcpICsKICAgCiAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTEsIDEpLCBsaW5ldHlwZSA9ICJkb3R0ZWQiLCBzaXplID0gLjUpICsKICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDEpLCBsaW5ldHlwZSA9ICJkb3R0ZWQiLCBzaXplID0gLjUpICsgCiAgICNzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoLTUuMCwtMi41LC0xLjAsMC4wLDEuMCwyLjUsNS4wLDcuNSksbGltaXRzID0gYygtNSw3LjUpKSArCiAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygtNC4wLC0zLjAsLTIuMCwtMS4wLDAuMCwxLjAsMi4wLDMuMCw0LjAsNS4wLDYuMCksbGltaXRzID0gYygtNCw2KSkgKwoKICAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMS4xLCB5ID0gMjEsIHhlbmQgPSA0LCB5ZW5kID0gMjEpLCBjb2xvcj10aW1lM19jb2xbWzFdXSwgI3k9MTYuNQogICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpKSArCiAgIGFubm90YXRlKCJ0ZXh0Iix4PTIuNiwgeT0yMi41LCBzaXplPTIsIGxhYmVsPSJIaWdoIGFidW5kYW50XG5pbiBhY3V0ZSBtYWxhcmlhIikgKyAjeT0xNy42CiAgIAogICBnZW9tX3NlZ21lbnQoYWVzKHggPSAtMS4xLCB5ID0gMjEsIHhlbmQgPSAtNCwgeWVuZCA9IDIxKSxjb2xvcj10aW1lM19jb2xbWzFdXSwKICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSkgKwogICBhbm5vdGF0ZSgidGV4dCIseD0tMi42LCB5PTIyLjUsIHNpemU9MiwgbGFiZWw9IkxvdyBhYnVuZGFudFxuaW4gYWN1dGUgbWFsYXJpYSIpICsgI3k9MTcuMQogICAKICAgbGFicyh4PSJFc3RpbWF0ZWQgZGlmZmVyZW5jZSAoTlBYKSBhdCBhY3V0ZSBjb21wYXJlZCB0byBjb252YWxlc2NlbmNlIiwKICAgICAgICB5PSItbG9nMTAoYWRqLiBwLXZhbHVlKSIpICsKICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NikpICsKICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYyh0aW1lM19jb2xbWzNdXSx0aW1lM19jb2xbWzFdXSkpKQpgYGAKCgoKIyMgRmlndXJlIDFHCmBgYHtyfQpobS5pbnB1dCA8LSBkYXRhLndpZGUgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlICU+JSBkcGx5cjo6c2VsZWN0KERBaWQsc3R1ZHlfaWQsIHNhbXBsZV9pZCwgVGltZSksYnk9InNhbXBsZV9pZCIpICU+JSAKICBkcGx5cjo6ZmlsdGVyKFRpbWU9PSJBY3V0ZSIpCgp0b3AyNSA8LSBkYXAucmVzICU+JSBkcGx5cjo6ZmlsdGVyKEZEUj09VFJVRSkgJT4lCiAgYXJyYW5nZShkZXNjKGFicyhsb2dGQykpLGRlc2MocC5hZGopKSAlPiUKICBtdXRhdGUodXBfZG93biA9IGlmZWxzZShsb2dGQz4wLCJ1cCIsImRvd24iKSkgJT4lIAogIGRwbHlyOjpncm91cF9ieSh1cF9kb3duKSAlPiUgCiAgc2xpY2VfaGVhZChuPTI1KQoKdG9wMjUuc3BsaXQgPC0gdG9wMjUgJT4lIGNvbHVtbl90b19yb3duYW1lcygiQXNzYXkiKSAlPiUgdHJhbnNtdXRlKGRpcmVjdGlvbiA9IGZhY3RvcihkaXJlY3Rpb24sIGxldmVscyA9IGMoInVwIiwiZG93biIpLCBsYWJlbHMgPSBjKCJoaWdoIiwibG93IikpKQoKbm9ybS5kZiA8LSBobS5pbnB1dCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGVfaWQiKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtYyhEQWlkLFRpbWUsc3R1ZHlfaWQpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjKHRvcDI1JEFzc2F5KSkgJT4lIAogIHQoKSAlPiUgc2NhbGUoKQoKIyMgPT0gQ29tcGxleEhlYXRtYXAgPT0gIyMKKGFjdXRlLm5weC50b3AyNS5obSA8LSBub3JtLmRmICU+JSAKICAgIHNjYWxlKCkgJT4lIAogICAgSGVhdG1hcChuYW1lPSJzY2FsZWRcbk5QWCIsCiAgICAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29sdW1ucyA9ICJzcGVhcm1hbiIsCiAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kX2NvbHVtbnM9IndhcmQuRDIiLAogICAgICAgICAgICAKICAgICAgICAgICAgdG9wX2Fubm90YXRpb24gPSBIZWF0bWFwQW5ub3RhdGlvbihkZiA9IGRhdGEuZnJhbWUoc2FtcGxlX2lkID0gY29sbmFtZXMoLikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwYXJhdGUoc2FtcGxlX2lkLCBpbnRvID0gYygic3R1ZHlfaWQiLCJUaW1lIiksc2VwPSJcXHwiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oc3ViamVjdFRhYmxlICU+JSB0cmFuc211dGUoc3R1ZHlfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kZW1pYyA9IGZhY3RvcihjYXNlX3doZW4oZW5kZW1pYz09InByaW1hcnlfaW5mZWN0ZWQifiJwcmltYXJ5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZGVtaWM9PSJwcmV2aW91c2x5X2V4cG9zZWQifiJwcmV2aW91c2x5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0PU5BKSxsZXZlbHM9YygicHJpbWFyeSIsInByZXZpb3VzbHkiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V2ZXJlXzUgPSBpZmVsc2Uoc2V2ZXJlXzU9PTEsInllcyIsIm5vIikpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoLXN0dWR5X2lkLC1UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaW1wbGVfYW5ub19zaXplID0gdW5pdCgyLCAibW0iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2Fubm90YXRpb25fbmFtZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9sZWdlbmRfcGFyYW0gPSBsaXN0KGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDMsICJtbSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JpZF93aWR0aCA9IHVuaXQoMywgIm1tIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xhYmVsID0gbGlzdChzZXZlcmVfNSA9ICJTZXZlcmUgbWFsYXJpYVxuKFdITykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZGVtaWMgPSAiZXhwb3N1cmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3QoZW5kZW1pYyA9ICBjKCJwcmV2aW91c2x5Ij0gIiNGMUEzNDAiLCJwcmltYXJ5Ij0gIiM5OThFQzMiKSwjZW5kZW1pYzJfY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXZlcmVfNSA9IGMoInllcyI9InRvbWF0byIsIm5vIj0iZ3JleTgwIikpLCNzZXZlcmVfNV9jb2wpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2g9ImNvbHVtbiIpLAogICAgICAgICAgICAKICAgICAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGLAogICAgICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gOCksCiAgICAgICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBUUlVFLAogICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogICAgICAgICAgICBjb2x1bW5fZGVuZF9yZW9yZGVyID0gVFJVRSwKICAgICAgICAgICAgcm93X2RlbmRfcmVvcmRlcj0xLXJvd1N1bXMoYWJzKG5vcm0uZGYpKSwKICAgICAgICAgICAgY2x1c3Rlcl9yb3dfc2xpY2VzID0gRkFMU0UsCiAgICAgICAgICAgIHJvd19kZW5kX3dpZHRoID0gdW5pdCgwLjUsICJjbSIpLCAKICAgICAgICAgICAgY29sdW1uX2RlbmRfaGVpZ2h0ID0gdW5pdCgwLjUsICJjbSIpLCAKICAgICAgICAgICAgcmFzdGVyX3Jlc2l6ZV9tYXQgPSBtZWFuLAogICAgICAgICAgICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgICBzaG93X3Jvd19uYW1lcyA9IFRSVUUsCiAgICAgICAgICAgIHJvd19zcGxpdCA9IHRvcDI1LnNwbGl0LAogICAgICAgICAgICByb3dfZ2FwID0gdW5pdCgwLjA1LCJjbSIpLAogICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDMsICJtbSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KDMsICJtbSIpKSwKICAgICAgICAgICAgaGVpZ2h0ID0gbmNvbCguKSp1bml0KDEuNCwgIm1tIiksCiAgICAgICAgICAgIHdpZHRoID0gbmNvbCguKSp1bml0KC4xNCwibW0iKQogICAgKSkKYGBgCgojIyBGaWd1cmUgMUgKYGBge3J9CnRvcDEwdXAgPC0gZGFwLnJlcyAlPiUgZHBseXI6OmZpbHRlcihGRFI9PVRSVUUpICU+JQogIGFycmFuZ2UoZGVzYyhhYnMobG9nRkMpKSxkZXNjKHAuYWRqKSkgJT4lCiAgbXV0YXRlKHVwX2Rvd24gPSBpZmVsc2UobG9nRkM+MCwidXAiLCJkb3duIikpICU+JSAKICBmaWx0ZXIodXBfZG93bj09InVwIikgJT4lIAogIGhlYWQobj0xMCkgJT4lCiAgcHVsbChBc3NheSkKCih2aW9saW5fbWFsYXJpYV90b3AxMCA8LSBkYXRhLmxvbmcgJT4lIAogICBpbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgZHBseXI6OnNlbGVjdChEQWlkLFRpbWUsc2FtcGxlX2lkLHN0dWR5X2lkKSwKICAgICAgICAgICAgICBieT0ic2FtcGxlX2lkIikgJT4lIAogICBkcGx5cjo6ZmlsdGVyKEFzc2F5ICVpbiUgYyh0b3AxMHVwKSkgJT4lIAogICBtdXRhdGUoQXNzYXkgPSBmYWN0b3IoQXNzYXksIGxldmVscyA9IHRvcDEwdXApKSAlPiUgCiAgIAogICBnZ3Bsb3QoYWVzKHg9VGltZSwgeT1OUFgsIGNvbG9yPVRpbWUsZmlsbD1UaW1lKSkgKyAKICAgZ2VvbV9saW5lKGFlcyhncm91cD1zdHVkeV9pZCksIGNvbG9yPSJncmV5IixhbHBoYT0uNixzaXplPS4yKSsKICAgZ2VvbV92aW9saW4odHJpbSA9IEYsYWxwaGE9LjIsbHdkPS4yNSkgKwogICBnZW9tX2JveHBsb3QoYWxwaGE9MSx3aWR0aD0wLjI1LGNvbG9yPSJibGFjayIsb3V0bGllci5zaXplID0gMC41LCBmYXR0ZW4gPSAxLGx3ZD0uMjUsc2hvdy5sZWdlbmQgPSBGKSArCiAgIGZhY2V0X3dyYXAofkFzc2F5LG5jb2wgPSA1LHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgIHRoZW1lX21pbmltYWwoKSArCiAgIGxhYnMoeD0iIikgKwogICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz10aW1lM19jb2wpICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXRpbWUzX2NvbCkpCmBgYAoKIyMgRmlndXJlIDFJCmBgYHtyfQp0b3AxMGRvd24gPC0gZGFwLnJlcyAlPiUgZHBseXI6OmZpbHRlcihGRFI9PVRSVUUpICU+JQogIGFycmFuZ2UoZGVzYyhhYnMobG9nRkMpKSxkZXNjKHAuYWRqKSkgJT4lCiAgbXV0YXRlKHVwX2Rvd24gPSBpZmVsc2UobG9nRkM+MCwidXAiLCJkb3duIikpICU+JSAKICBmaWx0ZXIodXBfZG93bj09ImRvd24iKSAlPiUgCiAgaGVhZChuPTEwKSAlPiUKICBwdWxsKEFzc2F5KQoKKHZpb2xpbl9tYWxhcmlhX3RvcDEwX2Rvd24gPC0gZGF0YS5sb25nICU+JSAKICAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUgJT4lIGRwbHlyOjpzZWxlY3QoREFpZCxUaW1lLHNhbXBsZV9pZCxzdHVkeV9pZCksCiAgICAgICAgICAgICAgYnk9InNhbXBsZV9pZCIpICU+JSAKICAgZHBseXI6OmZpbHRlcihBc3NheSAlaW4lIGModG9wMTBkb3duKSkgJT4lIAogICBtdXRhdGUoQXNzYXkgPSBmYWN0b3IoQXNzYXksIGxldmVscyA9IHRvcDEwZG93bikpICU+JSAKICAgIGdncGxvdChhZXMoeD1UaW1lLCB5PU5QWCwgY29sb3I9VGltZSxmaWxsPVRpbWUpKSArIAogICAgZ2VvbV9saW5lKGFlcyhncm91cD1zdHVkeV9pZCksIGNvbG9yPSJncmV5IixhbHBoYT0uNixzaXplPS4yKSsKICAgIGdlb21fdmlvbGluKHRyaW0gPSBGLGFscGhhPS4yLGx3ZD0uMjUpICsKICAgIGdlb21fYm94cGxvdChhbHBoYT0xLHdpZHRoPTAuMjUsY29sb3I9ImJsYWNrIixvdXRsaWVyLnNpemUgPSAwLjUsIGZhdHRlbiA9IDEsbHdkPS4yNSxzaG93LmxlZ2VuZCA9IEYpICsKICAgIGZhY2V0X3dyYXAofkFzc2F5LG5jb2wgPSA1LHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh4PSIiKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXRpbWUzX2NvbCkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXRpbWUzX2NvbCkpCmBgYAoKIyMgU3VwcGxlbWVudGFyeSBUYWJsZSBTMSAKYGBge3J9CiMjZ3RzdW1tYXJ5CmxpYnJhcnkoZ3RzdW1tYXJ5KQpzdWJqZWN0VGFibGUgJT4lIAogIG11dGF0ZSh5ZWFyc19zaW5jZV9lbmRlbWljID0gY2FzZV93aGVuKGVuZGVtaWM9PSJwcmltYXJ5In5OQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHllYXJzX3NpbmNlX2VuZGVtaWMpLAogICAgICAgICAKICAgICAgICAgU09GQV90b3RhbCA9IGFzLm51bWVyaWMoU09GQV90b3RhbCksCiAgICAgICAgIGVuZGVtaWMgPSBzdHJfcmVwbGFjZShlbmRlbWljLCJfIiwiICIpLAogICAgICAgICBzZXZlcmVfNSA9IGNhc2Vfd2hlbihzZXZlcmVfNT09MSB+ICJzZXZlcmUiLC5kZWZhdWx0ID0gIm5vbi1zZXZlcmUiKSkgJT4lIAogIHRibF9zdW1tYXJ5KGluY2x1ZGUgPSBjKHNleCwgYWdlLCBlbmRlbWljLCB5ZWFyc19zaW5jZV9lbmRlbWljLCBkaWZmX2FjdXRlU2FtcGxlX3NwdF9jdXJyZW50LmFicywgaW5mX3JiY19tYXgsIHNldmVyZV81LFNPRkFfdG90YWwpLAogICAgICAgICAgICAgIAogICAgICAgICAgICAgIHN0YXRpc3RpYyA9IGxpc3QoYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVkaWFufSAoe21pbn0te21heH0pIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbF9jYXRlZ29yaWNhbCgpIH4gIntufSAvIHtOfSAoe3B9JSkiCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICMgZGlnaXRzID0gYWxsX2NvbnRpbnVvdXMoKSB+IDIsCiAgICAgICAgICAgICBkaWdpdHMgPSBjKGFnZSB+IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX3NpbmNlX2VuZGVtaWMgfiAwLAogICAgICAgICAgICAgICAgICAgICAgICBkaWZmX2FjdXRlU2FtcGxlX3NwdF9jdXJyZW50LmFicyB+IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIGluZl9yYmNfbWF4IH4gMiksCiAgICAgICAgICAgICAgbGFiZWwgPSBjKGVuZGVtaWMgfiAiUHJldmlvdXMgbWFsYXJpYSBleHBvc3VyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGFnZSB+ICJBZ2UiLAogICAgICAgICAgICAgICAgICAgICAgICBzZXggfiJTZXgiLAogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19zaW5jZV9lbmRlbWljIH4gIlllYXJzIHNpbmNlIGxpdmluZyBpbiBlbmRlbWljIGFyZWEiLAogICAgICAgICAgICAgICAgICAgICAgICBpbmZfcmJjX21heCB+ICJQYXJhc2l0ZW1pYSBbJV0iLAogICAgICAgICAgICAgICAgICAgICAgICBTT0ZBX3RvdGFsIH4gIlNPRkEgc2NhbGUiLAogICAgICAgICAgICAgICAgICAgICAgICBkaWZmX2FjdXRlU2FtcGxlX3NwdF9jdXJyZW50LmFicyB+ICJEYXlzIHNpbmNlIHN5bXB0b20gb25zZXQiLAogICAgICAgICAgICAgICAgICAgICAgICBzZXZlcmVfNSA9ICJTZXZlcmUgbWFsYXJpYSBhY2NvcmRpbmcgdG8gV0hPIGNyaXRlcmlhXG4ocmVmIFdITyBHdWlkZWxpbmVzIGZvciB0aGUgdHJlYXRtZW50IG9mIE1hbGFyaWEgLCAzcmQgZWRpdGlvbiwgMjAxNSkiKSwKICAgICAgICAgICAgICBtaXNzaW5nID0gIm5vIgogICkgJT4lIAogIGFkZF9uKCkgJT4lICMgYWRkIGNvbHVtbiB3aXRoIHRvdGFsIG51bWJlciBvZiBub24tbWlzc2luZyBvYnNlcnZhdGlvbnMKICBtb2RpZnlfaGVhZGVyKGxhYmVsID0gIioqVmFyaWFibGUqKiIpICU+JSAjIHVwZGF0ZSB0aGUgY29sdW1uIGhlYWRlcgogIGJvbGRfbGFiZWxzKCkgCmBgYAoKIyMgU3VwcGxlbWVudGFyeSBUYWJsZSBTMgoKYGBge3J9CmRhcHMub3V0IDwtIGxtZV9yZXNfcGFkaiAlPiUgCiAgdHJhbnNtdXRlKFVuaVByb3QsIAogICAgICAgICAgICBBc3NheSwKICAgICAgICAgICAgZXN0aW1hdGUsCiAgICAgICAgICAgIGNvbnRyYXN0LCAKICAgICAgICAgICAgU0UsCiAgICAgICAgICAgIENJID0gMS45NipTRSwKICAgICAgICAgICAgZGYsCiAgICAgICAgICAgIHQucmF0aW8sCiAgICAgICAgICAgIHAudmFsdWUsIAogICAgICAgICAgICBwLmFkaiwKICAgICAgICAgICAgcHJlZmZlcmVkX21vZGVsID0gY2FzZV93aGVuKEFzc2F5ICVpbiUgYXNzYXlfYmV0dGVyX2NvbXBsZXhfbW9kZWwgfiAiY29tcGxleCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9ICJzaW1wbGUiKSkKI2RhcHMub3V0JT4lICB3cml0ZV90c3YocGFzdGUwKHJlc3VsdC5kaXIsIlN1cHBsZW1lbnRhcnlfVGFibGVTMl9EaWZmZXJlbnRpYWxseUFidW5kYW50UHJvdGVpbnMudHN2IikpCmRhcHMub3V0ICU+JSBoZWFkKCkKYGBgCgojIyBTdXBwbGVtZW50YXJ5IEZpZ3VyZSAxCiMjIyBGaWd1cmUgUzFBCgpgYGB7cn0KdG1wIDwtIGRhdGEubG9uZyAlPiUgCiAgZGlzdGluY3Qoc2FtcGxlX2lkKSAKaG1fbWF0IDwtIHRtcCAlPiUgCiAgc2VwYXJhdGUoc2FtcGxlX2lkLCBpbnRvID0gYygic3R1ZHlfaWQiLCJUaW1lIiksc2VwID0gIlxcfCIscmVtb3ZlID0gVCkgJT4lIAogICBtdXRhdGUoVGltZSA9IGZhY3RvcihUaW1lLCBsZXZlbHM9YygiQWN1dGUiLCJEMTAiLCJNMTIiKSksCiAgICAgICAgICBkdW1teSA9IFRpbWUpICU+JSAKICAKICBncm91cF9ieShzdHVkeV9pZCkgJT4lIAogIG11dGF0ZShuID0gbigpKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFRpbWUsIHZhbHVlc19mcm9tID0gZHVtbXkpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1uKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9pZCIpICU+JSAKICByZWxvY2F0ZShBY3V0ZSxEMTAsTTEyKSAlPiUgCiAgdCgpIAoKKHNhbXBsZV9vdmVybGFwX2htIDwtIGhtX21hdCAlPiUgCiAgSGVhdG1hcChyb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGLAogICAgICAgICAgbmFfY29sID0gIndoaXRlIiwKICAgICAgICAgIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICByb3dfbmFtZXNfc2lkZSA9ICJsZWZ0IiwKICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICBjb2x1bW5fbmFtZXNfcm90ID0gNDUsCiAgICAgICAgICBzaG93X2hlYXRtYXBfbGVnZW5kID0gRiwKICAgICAgICAgIGNvbHVtbl9zcGxpdCA9IGRhdGEuZnJhbWUoc3R1ZHlfaWQgPSBjb2xuYW1lcyhobV9tYXQpKSAlPiUgCiAgICAgICAgICAgIGxlZnRfam9pbihzdWJqZWN0VGFibGUgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICB0cmFuc211dGUoc3R1ZHlfaWQsIGVuZGVtaWMpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKAogICAgICAgICAgICAgICAgICAgICAgICAgIHRpYmJsZShzdHVkeV9pZCA9IGMoIjIwMTQwMDMiLCIyMDEyUFQxMiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRlbWljID0gYygicHJpbWFyeV9pbmZlY3RlZCIsInByaW1hcnlfaW5mZWN0ZWQiKSkpKSAlPiUgIAogICAgICAgICAgICB0cmFuc211dGUoZW5kZW1pYz0gZmFjdG9yKGVuZGVtaWMsIGxldmVscz1jKCJwcmltYXJ5X2luZmVjdGVkIiwicHJldmlvdXNseV9leHBvc2VkIiksIGxhYmVscz0gYygicHJpbWFyeSBpbmZlY3RlZCIsInByZXZpb3VzbHkgZXhwb3NlZCIpKSksCiAgICAgICAgICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgCiAgICAgICAgICByZWN0X2dwID0gZ3Bhcihjb2wgPSAid2hpdGUiLCBsd2QgPSAuNSksCiAgICAgICAgICB3aWR0aCA9IG5jb2woLikqdW5pdCgxLCAibW0iKSwgCiAgICAgICAgICBoZWlnaHQgPSBucm93KC4pKnVuaXQoMiwgIm1tIiksCiAgICAgICAgICAjaGVpZ2h0ID0gbmNvbCguKSp1bml0KDEuNCwgIm1tIiksCiAgICAgICAgICAjICB3aWR0aCA9IG5jb2woLikqdW5pdCguNSwibW0iKSwKICAgICAgICAgIGJvcmRlcl9ncCA9IGdwYXIoY29sID0gImJsYWNrIiwgbHR5ID0gLjkpLAogICAgICAgICAgY29sID0gIHRpbWUzX2NvbCwKICAgICAgICAgIHRvcF9hbm5vdGF0aW9uID0gSGVhdG1hcEFubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKHN0dWR5X2lkID0gY29sbmFtZXMoLikpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oc3ViamVjdFRhYmxlICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc211dGUoc3R1ZHlfaWQsIGVuZGVtaWMpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWJibGUoc3R1ZHlfaWQgPSBjKCIyMDE0MDAzIiwiMjAxMlBUMTIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRlbWljID0gYygicHJpbWFyeV9pbmZlY3RlZCIsInByaW1hcnlfaW5mZWN0ZWQiKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KC1zdHVkeV9pZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDMsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2Fubm90YXRpb25fbmFtZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChlbmRlbWljID0gIGVuZGVtaWMyX2NvbCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoPSJjb2x1bW4iKSkKKQoKYGBgCgojIyMgRmlndXJlIFMxQgoKYGBge3J9CihhY3V0ZV9leHBvc3VyZV92b2xjYW5vIDwtIGxtZV9yZXMgJT4lIAogIHVubmVzdChjb2xzPXBvc3Rob2MudGltZV9leHBvc3VyZSkgJT4lIAogIGZpbHRlcihjb250cmFzdCAlaW4lYygiQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIE0xMiBwcmltYXJ5X2luZmVjdGVkIiwKICAgICAgICAgICAgICAgICAgICAiQWN1dGUgcHJldmlvdXNseV9leHBvc2VkIC0gTTEyIHByZXZpb3VzbHlfZXhwb3NlZCIpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShjb250cmFzdCkgJT4lIAogIG11dGF0ZShwLmFkaiA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIiksCiAgICAgICAgIEZEUiA9IGlmZWxzZShwLmFkaiA8PSAwLjAxLCBUUlVFLEZBTFNFKSkgJT4lIAogIGFycmFuZ2UocC5hZGopICU+JSAKICB0cmFuc211dGUoQXNzYXksY29udHJhc3QsIGVzdGltYXRlLFNFLGRmLHQucmF0aW8sIHAudmFsdWUsIHAuYWRqLCBGRFIsCiAgICAgICAgICAgIGNvbG9yID0gY2FzZV93aGVuKEZEUj09VCAmIGNvbnRyYXN0PT0iQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIE0xMiBwcmltYXJ5X2luZmVjdGVkIiB+ICJwcmltYXJ5X2luZmVjdGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRkRSPT1UICYgY29udHJhc3Q9PSJBY3V0ZSBwcmV2aW91c2x5X2V4cG9zZWQgLSBNMTIgcHJldmlvdXNseV9leHBvc2VkIiB+ICJwcmV2aW91c2x5X2V4cG9zZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIGNvbnRyYXN0ID0gZmFjdG9yKGNvbnRyYXN0LCBsZXZlbHM9YygiQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIE0xMiBwcmltYXJ5X2luZmVjdGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY3V0ZSBwcmV2aW91c2x5X2V4cG9zZWQgLSBNMTIgcHJldmlvdXNseV9leHBvc2VkIikpLAogICAgICAgICAgICBsYWJlbF80X2NvbXBsZXhfYmV0dGVyID0gY2FzZV93aGVuKEFzc2F5ICVpbiUgYXNzYXlfYmV0dGVyX2NvbXBsZXhfbW9kZWwgJiBjb250cmFzdD09IkFjdXRlIHByaW1hcnlfaW5mZWN0ZWQgLSBNMTIgcHJpbWFyeV9pbmZlY3RlZCIgfiBBc3NheSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BKSkgJT4lIAogIAogIGdncGxvdChhZXMoeT1mY3RfcmVvcmRlcihBc3NheSwgZXN0aW1hdGUpLCB4PWVzdGltYXRlLCBjb2xvcj1jb2xvcikpICsKIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9ZW5kZW1pYzJfY29sLCBuYS52YWx1ZSA9ICJncmV5IixicmVha3MgPSBjKCJwcmltYXJ5X2luZmVjdGVkIiwicHJldmlvdXNseV9leHBvc2VkIikpICsKICBsYWJzKGNvbG9yPU5VTEwsCiAgICAgICB4PSJFc3RpbWF0ZWQgZGlmZmVyZW5jZSArLSA5NSUgQ0kgYXQgYWN1dGUgZm9yXG5wcmltYXJ5IGluZmVjdGVkIGFuZCBwcmV2aW91c2x5IGV4cG9zZWQgaW5kaXZpZHVhbHNcbmNvbXBhcmVkIHRvIE0xMiIsIyJFc3RpbWF0ZWQgZGlmZmVyZW5jZSAoTlBYKSBhdCBhY3V0ZSBjb21wYXJlZCB0byBoZWFsdGh5LXN0YXRlIGF0IE0xMiIsCiAgICAgICB5PSJyYW5rZWQgcHJvdGVpbnMiKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeG1pbj1lc3RpbWF0ZSAtIDEuOTYqU0UsIAogICAgICAgICAgICAgICAgICAgIHhtYXg9ZXN0aW1hdGUgKyAxLjk2KlNFKSwKICAgICAgICAgICAgICAgIGxpbmV3aWR0aD0uMiwgICAgIyBUaGlubmVyIGxpbmVzCiAgICAgICAgICAgICAgICB3aWR0aD0uMiwKICAgICAgICAgICAgICAgIGFscGhhPS4xKSArCiAgICBnZW9tX3BvaW50KGFscGhhPTAuNyxzaXplPS41LCBzaGFwZT0xNikgKwogICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWxhYmVsXzRfY29tcGxleF9iZXR0ZXIpLCNpZmVsc2UoQXNzYXkgJWluJSBhc3NheV9iZXR0ZXJfY29tcGxleF9tb2RlbCAmIGNvbG9yPT0icHJpbWF5X2luZmVjdGVkIixBc3NheSxOQSkpLAogICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRiwKICAgICAgICAgICAgICAgICAgIGNvbG9yPSJibGFjayIsCiAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAuNSwKICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEsCiAgICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IC43NSwKICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAieSIsCiAgICAgICAgICAgICAgICAgICAgc2l6ZT0xLAogICAgICAgICAgICAgICAgICAgI2xhYmVsLnNpemUgPSAuMSwKICAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LmFscGhhPS4xLAogICAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IDE2KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHR5PTIsIGFscGhhPS42KSArCiAgdGhlbWVfbWluaW1hbCgpKQpgYGAKCgpgYGB7cn0KbG1lX3Jlc19leHBvIDwtIGxtZV9yZXMgJT4lIAogIHVubmVzdChjb2xzPSJwb3N0aG9jLnRpbWVfZXhwb3N1cmUiKSAlPiUgCiAgZmlsdGVyKGNvbnRyYXN0PT0iQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIEFjdXRlIHByZXZpb3VzbHlfZXhwb3NlZCIpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShwLmFkaiA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIiksCiAgICAgICAgICAgICAgICAgIEZEUiA9IGlmZWxzZShwLmFkaiA8PSAwLjAxLCBUUlVFLEZBTFNFKSkgJT4lIAogIGZpbHRlcihGRFI9PVQpICU+JSAKICBhcnJhbmdlKC1lc3RpbWF0ZSkgCgphc3NheXNfc2lnbmlmaWNhbnRfZGlmZmVyZW50X2F0X2FjdXRlX2V4cCA8LSBsbWVfcmVzX2V4cG8gJT4lIAogIHB1bGwoQXNzYXkpCmBgYAoKIyMjIEZpZ3VyZSBTMUMKCmBgYHtyfQpsaWJyYXJ5KGV1bGVycikKCnBsb3QoZXVsZXIobGlzdCgiYWN1dGUiID0gbG1lX3Jlc19wYWRqICU+JSBmaWx0ZXIoRkRSPT1UKSAlPiUgcHVsbChBc3NheSksCiAgICAgICAgICAgICAgICAgICJleHBvc3VyZSI9IGxtZV9yZXNfZXhwbyAlPiUgZmlsdGVyKEZEUj09VCkgJT4lIHB1bGwoQXNzYXkpKSksIyBhc3NheXNfc2lnbmlmaWNhbnRfZGlmZmVyZW50X2F0X2FjdXRlX2V4cCkpLCNsbWVfcmVzX2V4cG8gJT4lIGZpbHRlcihGRFI9PVQpICU+JSBwdWxsKEFzc2F5KSkpLAogICAgICAgIGZpbGxzID0gYygiI0M1MUI3RCIsCiAgICAgICAgICAgICAgICAgICJ3aGl0ZSIpLAogICAgICAgcXVhbnRpdGllcyA9IFRSVUUsCiAgICAgICBsdHkgPSAxLCMxOjMsCiAgICAgICBmb250c2l6ZT0xLAogICAgICAgbGFiZWxzID0gbGlzdChmb250c2l6ZT01KSwKICAgICAgIHNoYXBlID0gImVsbGlwc2UiLGFkanVzdF9sYWJlbHMgPSBUKQoKYWN1dF9leHBvc3VyZV9pbnRlcnNlY3QgPC0gaW50ZXJzZWN0KGFzc2F5c19zaWduaWZpY2FudF9kaWZmZXJlbnRfYXRfYWN1dGVfZXhwLCNsbWVfcmVzX2V4cG8gJT4lIGZpbHRlcihGRFI9PVQpICU+JSBwdWxsKEFzc2F5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxtZV9yZXNfcGFkaiAlPiUgZmlsdGVyKEZEUj09VCkgJT4lIHB1bGwoQXNzYXkpKQpgYGAKCiMjIyBGaWd1cmUgUzFECgpgYGB7cn0KZGYgPC0gbG1lX3JlcyAlPiUgCiAgZmlsdGVyKEFzc2F5ICVpbiUgYXNzYXlzX3NpZ25pZmljYW50X2RpZmZlcmVudF9hdF9hY3V0ZV9leHApICU+JSAKICBtdXRhdGUoQXNzYXkgPSBmYWN0b3IoQXNzYXksIGxldmVscz1hc3NheXNfc2lnbmlmaWNhbnRfZGlmZmVyZW50X2F0X2FjdXRlX2V4cCkpICU+JSAKICB1bm5lc3QoY29scz1wb3N0aG9jLnRpbWVfZXhwb3N1cmUpICU+JSAKICBmaWx0ZXIoY29udHJhc3QgJWluJWMoIkFjdXRlIHByaW1hcnlfaW5mZWN0ZWQgLSBNMTIgcHJpbWFyeV9pbmZlY3RlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICJBY3V0ZSBwcmV2aW91c2x5X2V4cG9zZWQgLSBNMTIgcHJldmlvdXNseV9leHBvc2VkIikpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShjb2xvciA9IGNhc2Vfd2hlbihjb250cmFzdD09IkFjdXRlIHByaW1hcnlfaW5mZWN0ZWQgLSBNMTIgcHJpbWFyeV9pbmZlY3RlZCIgfiAicHJpbWFyeV9pbmZlY3RlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0PT0iQWN1dGUgcHJldmlvdXNseV9leHBvc2VkIC0gTTEyIHByZXZpb3VzbHlfZXhwb3NlZCIgfiAicHJldmlvdXNseV9leHBvc2VkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUKICMgcm93bmFtZXNfdG9fY29sdW1uKCJyb3dudW1iZXJzIikgJT4lIAogICNmaWx0ZXIoQXNzYXklaW4lYygiQ1hDTDEwIiwiSUZORyIsIkNYQ0w5IiwiVE5GU0YxM0IiKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoLShsbWUucmVzLnNpbXBsZTpwb3N0aG9jLnRpbWUpKSAKcmVxdWlyZShnZ3RleHQpCihhY3V0ZV9leHBvc3VyZV9zaWduaWZpY2FudCA8LSBkZiAlPiUgCiAgICBtdXRhdGUoeC5sYWJlbCA9IHBhc3RlKCI8c3BhbiBzdHlsZSA9ICdjb2xvcjogIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShBc3NheSAlaW4lIGFjdXRfZXhwb3N1cmVfaW50ZXJzZWN0ICwgInBpbmsiLCAiYmxhY2siKSwKICAgICAgICAgICAgICAgICAgICAgICAgICI7Jz4iLAogICAgICAgICAgICAgICAgICAgICAgICAgQXNzYXksCiAgICAgICAgICAgICAgICAgICAgICAgICAiPC9zcGFuPiIsIHNlcCA9ICIiKSwKICAgICAgICAgeC5sYWJlbCA9IGZjdF9yZW9yZGVyKHgubGFiZWwsIGFzLmNoYXJhY3RlcihBc3NheSkpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eC5sYWJlbCwgeT1lc3RpbWF0ZSwgY29sb3I9Y29sb3IpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xNixzaXplPS41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVuZGVtaWMyX2NvbCwgYnJlYWtzID0gYygicHJpbWFyeV9pbmZlY3RlZCIsInByZXZpb3VzbHlfZXhwb3NlZCIpKSArCgogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGx0eT0yLCBhbHBoYT0uMykgKwogIyAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKHNob3cubGVnZW5kID0gRiwgY29sb3I9ImJsYWNrIikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49ZXN0aW1hdGUgLSAxLjk2KlNFLCAKICAgICAgICAgICAgICAgICAgICB5bWF4PWVzdGltYXRlICsgMS45NipTRSksCiAgICAgICAgICAgICAgICBsaW5ld2lkdGg9LjIsICAgICMgVGhpbm5lciBsaW5lcwogICAgICAgICAgICAgICAgd2lkdGg9LjIsCiAgICAgICAgICAgICAgICBhbHBoYT0uNSkgKwogIGxhYnMoeD1OVUxMLAogICAgICAgY29sb3IgPSBOVUxMLAogICAgICAgeT0iRXN0aW1hdGVkIGRpZmZlcmVuY2UgKy0gOTUlIENJIGF0IGFjdXRlIGZvclxucHJpbWFyeSBpbmZlY3RlZCBhbmQgcHJldmlvdXNseSBleHBvc2VkIGluZGl2aWR1YWxzXG5jb21wYXJlZCB0byBNMTJcbiIpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKGFuZ2xlID0gOTAsIGhqdXN0ID0gMSx2anVzdD0wLjUsIHNpemU9NiksCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQopCmBgYAoKCiMjIFN1cHBsZW1lbnRhcnkgRmlndXJlIDIKCioqcmVsYXRlZCB0byBtYWluIEZpZ3VyZSAyKioKCiMjIyBGaWd1cmUgUzJBCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKc3VwcGxlbWVudGFyeV9jb3ZhcmlhdGVzLnJlcyA8LSBkYXRhLmxvbmcgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIAogIGlubmVyX2pvaW4oc3ViamVjdFRhYmxlLCBieT0ic3R1ZHlfaWQiKSAlPiUgCiAgZmlsdGVyKFRpbWUgIT0gIkQxMCIpICU+JSAKICBtdXRhdGUoVGltZSA9IGZhY3RvcihUaW1lLCBsZXZlbHM9YygiQWN1dGUiLCJNMTIiKSkpICU+JSAKICBncm91cF9ieShBc3NheSkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKGxtZS5yZXMgPSBwdXJycjo6bWFwKGRhdGEsIH4gbG1lclRlc3Q6OmxtZXIoTlBYIH4gVGltZSArIHllYXJfaW5jbHVzaW9uICsgc2V4ICsgYWdlICsgZW5kZW1pYyArIGluZl9yYmNfbWF4ICsgKDF8c3R1ZHlfaWQpLCBSRU1MID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSAuKSksCiAgICAgICAgIGxtZS50aWR5ID0gcHVycnI6Om1hcChsbWUucmVzLCB+IGJyb29tLm1peGVkOjp0aWR5KC4pKSkKCnN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXNfIDwtIHN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXMgJT4lIAogIHVubmVzdChjb2xzID0gbG1lLnRpZHkpICU+JSAKICBmaWx0ZXIoZWZmZWN0ID09ImZpeGVkIiwgCiAgICAgICAgIHRlcm0hPSIoSW50ZXJjZXB0KSIpICU+JSAKICAjZmlsdGVyKHRlcm0gIT0gIlJlc2lkdWFscyIpICU+JSAKICBtdXRhdGUodGVybSA9IGNhc2Vfd2hlbih0ZXJtPT0ic2V4bWFsZSJ+InNleCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGVybT09ImVuZGVtaWNwcmltYXJ5X2luZmVjdGVkIn4iZW5kZW1pYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGVybT09IlRpbWVNMTIifiJUaW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHRlcm0pKSAlPiUgCiAgbXV0YXRlKHAuYWRqID0gcC5hZGp1c3QocC52YWx1ZSwgbWV0aG9kPSJmZHIiKQogICkgJT4lCiAgbXV0YXRlKHRlcm0uY29sID0gY2FzZV93aGVuKHAuYWRqID4gMC4wMSB+IE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwLmFkaiA8PSAwLjAxIH4gdGVybSkpCgpjb3YuY29sb3JzIDwtIGMoIlRpbWUiID0gdGltZTNfY29sW1sxXV0sc2V0TmFtZXMoYnJld2VyLnBhbCg3LCJEYXJrMiIpW2MoMTozLDU6OCldLCBjKCJzZXgiLCJlbmRlbWljIiwiYWdlIiwieWVhcl9pbmNsdXNpb24iLCJpbmZfcmJjX21heCIpKSkKCmNvdW50cy5mZHIgPC0gc3VwcGxlbWVudGFyeV9jb3ZhcmlhdGVzLnJlc18gJT4lIAogIGZpbHRlcihwLmFkaiA8PSAwLjAxKSAlPiUgCiAgZ3JvdXBfYnkodGVybSkgJT4lIAogIGNvdW50KHNvcnQgPSBUKQoKKGRhdGEuYW92LnBsb3QgPC0gc3VwcGxlbWVudGFyeV9jb3ZhcmlhdGVzLnJlc18gJT4lIAogICAgbXV0YXRlKHRlcm0gPSBmYWN0b3IodGVybSwgbGV2ZWxzPWNvdW50cy5mZHIkdGVybSkpICU+JSAKICAgIGdncGxvdChhZXMoeD10ZXJtLCB5PSAtbG9nMTAocC5hZGopKSkgKyAKICAgIGdlb21faml0dGVyKGFlcyhjb2xvcj10ZXJtLmNvbCksIHNob3cubGVnZW5kID0gRixzaXplPS4yNSxhbHBoYT0uNyxzaGFwZT0xNikgKwogICAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9IC4gJT4lIGdyb3VwX2J5KHRlcm0pICU+JSBzbGljZV9tYXgobj01LG9yZGVyX2J5ID0gLWxvZzEwKHAuYWRqKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbD1Bc3NheSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRixmb3JjZSA9IC41LCBudWRnZV95ID0gLjI1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZT0wLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LmFscGhhPS4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAxNSwgY29sb3I9ImdyYXk0NSIpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdD0tbG9nMTAoMC4wMSksIAogICAgICAgICAgICAgICBsaW5ldHlwZSA9IDMpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3YuY29sb3JzKSArCiAgICAKICAgIGdlb21fdGV4dChkYXRhPWNvdW50cy5mZHIsYWVzKHg9dGVybSwgeT0tMS4yLCBsYWJlbD1uLCBjb2xvcj10ZXJtKSwgc2hvdy5sZWdlbmQgPSBGKSArCiAgICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz1jKCJhZ2UiID0gIkFnZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ5ZWFyX2luY2x1c2lvbiIgPSAiWWVhclxub2ZcbnNhbXBsaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNleCIgPSAiU2V4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImVuZGVtaWMiID0gIlByZXZpb3VzXG5leHBvc3VyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpbmZfcmJjX21heCIgPSAiUGFyYXNpdGVtaWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGltZSIgPSAiSW5mZWN0aW9uXG4oQWN1dGUgdnMgY29udmFsZXNjZW5jZSkiKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnMoeD1OVUxMLCAKICAgICAgICAgY29sb3I9TlVMTCkgKwogICAgdGhlbWUoKSkKYGBgCgoKCiMjIyBGaWd1cmUgUzJCCmBgYHtyfQpuMnNob3cgPC0gMwooYW5vdmEuc2V4LnBsb3QgPC0gc3VwcGxlbWVudGFyeV9jb3ZhcmlhdGVzLnJlc18gJT4lCiAgICBmaWx0ZXIodGVybT09InNleCIpICU+JQogICAgYXJyYW5nZShwLmFkaikgJT4lIAogICAgaGVhZChuPW4yc2hvdykgJT4lIAogICAgdW5uZXN0KGNvbHMgPSBkYXRhKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9VGltZSwgeT1OUFgsIGZpbGw9YXMuY2hhcmFjdGVyKHNleCkpKSArCiAgICBnZW9tX2JveHBsb3QoIGZhdHRlbiA9IDEsbHdkPS4yNSxvdXRsaWVyLnNpemUgPSAwLjUpICsKICAgIGZhY2V0X3dyYXAofkFzc2F5LCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnMoeD1OVUxMLAogICAgICAgICBmaWxsPSJTZXgiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBzZXgyX2NvbCkpCgooYW5vdmEuZW5kZW1pYy5wbG90IDwtIHN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXNfICU+JQogICAgZmlsdGVyKHRlcm09PSJlbmRlbWljIikgJT4lCiAgICBhcnJhbmdlKHAuYWRqKSAlPiUgCiAgICBoZWFkKG49bjJzaG93KSAlPiUgCiAgICB1bm5lc3QoY29scyA9IGRhdGEpICU+JSAKICAgIGdncGxvdChhZXMoeD1UaW1lLCB5PU5QWCwgZmlsbD1hcy5jaGFyYWN0ZXIoZW5kZW1pYykpKSArCiAgICBnZW9tX2JveHBsb3QoZmF0dGVuID0gMSxsd2Q9LjI1LG91dGxpZXIuc2l6ZSA9IDAuNSkgKwogICAgZmFjZXRfd3JhcCh+QXNzYXksIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh4PU5VTEwsCiAgICAgICAgIGZpbGw9IlByZXZpb3VzIGV4cG9zdXJlIikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZW5kZW1pYzJfY29sKSkKCihhbm92YS55ZWFyX2luY2x1c2lvbi5wbG90IDwtIHN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXNfICU+JQogICAgZmlsdGVyKHRlcm09PSJ5ZWFyX2luY2x1c2lvbiIpICU+JSBhcnJhbmdlKHAuYWRqKSAlPiUgCiAgICBoZWFkKG49bjJzaG93KSAlPiUgCiAgICB1bm5lc3QoY29scyA9IGRhdGEpICU+JSAKICAgIGdncGxvdChhZXMoeD1hcy5udW1lcmljKHllYXJfaW5jbHVzaW9uKSx5PU5QWCxjb2xvcj1UaW1lKSkgKwogICAgZ2VvbV9wb2ludChzaXplPS41KSArCiAgICBnZW9tX3Ntb290aChsaW5ld2lkdGg9MC40LAogICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygyMDExLDIwMjEpLGJyZWFrcyA9IGMoMjAxMSwyMDE2LDIwMjEpKSArIAogICAgZmFjZXRfd3JhcCh+QXNzYXksIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh4PSJZZWFyIG9mIGluY2x1c2lvbiIsCiAgICAgIGNvbG9yPSJTYW1wbGUgdGltZSBwb2ludCIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0aW1lM19jb2wpKQoKKGFub3ZhLmFnZS5wbG90IDwtIHN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXNfICU+JQogICAgZmlsdGVyKHRlcm09PSJhZ2UiKSAlPiUgYXJyYW5nZShwLmFkaikgJT4lIAogICAgaGVhZChuPW4yc2hvdykgJT4lIAogICAgdW5uZXN0KGNvbHMgPSBkYXRhKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9YXMubnVtZXJpYyhhZ2UpLHk9TlBYLGNvbG9yPVRpbWUpKSArCiAgICBnZW9tX3BvaW50KHNpemU9LjUpICsKICAgIGdlb21fc21vb3RoKGxpbmV3aWR0aD0wLjQsCiAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYpICsKICAgIGZhY2V0X3dyYXAofkFzc2F5LCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnModGl0bGU9IiIsCiAgICAgICAgIHg9IlllYXJzIiwKICAgICAgICAgY29sb3I9IkFnZSIpICsgCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdGltZTNfY29sKQopCgooYW5vdmEuaW5mX3JiY19tYXgucGxvdCA8LSBzdXBwbGVtZW50YXJ5X2NvdmFyaWF0ZXMucmVzXyAlPiUKICAgIGZpbHRlcih0ZXJtPT0iaW5mX3JiY19tYXgiKSAlPiUgYXJyYW5nZShwLmFkaikgJT4lIAogICAgaGVhZChuPW4yc2hvdykgJT4lIAogICAgdW5uZXN0KGNvbHMgPSBkYXRhKSAlPiUgCiAgICBmaWx0ZXIoVGltZT09IkFjdXRlIikgJT4lIAogICAgZ2dwbG90KGFlcyh4PWFzLm51bWVyaWMoaW5mX3JiY19tYXgpLHk9TlBYLGNvbG9yPWFzLm51bWVyaWMoaW5mX3JiY19tYXgpKSkgKwogICAgZ2VvbV9wb2ludChzaXplPS41KSArCiAgICBnZW9tX3Ntb290aChhZXMoY29sb3I9Li54Li4pLAogICAgICAgICAgICAgICAgbGluZXdpZHRoPTAuNCwKICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikgKwogICAgZmFjZXRfd3JhcCh+QXNzYXksIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh0aXRsZT0iIiwKICAgICAgICAgeD0iUGFyYXNpdGVtaWEsIGluZmVjdGVkIGVyeXRocm9jeXRlcyBbJV0iLAogICAgICAgICBjb2xvcj0iUGFyYXNpdGVtaWEgWyVdIikgKyAKICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iZ3JleSIsaGlnaD0iZGFya3JlZCIpCiAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0aW1lM19jb2wpCikKCihhbm92YS5wYW5lbCA8LSAoYW5vdmEuaW5mX3JiY19tYXgucGxvdCAvIAogICAgICAgICAgICAgICAgICAgYW5vdmEuZW5kZW1pYy5wbG90IC8KICAgICAgICAgICAgICAgICAgIGFub3ZhLnllYXJfaW5jbHVzaW9uLnBsb3QgLyAKICAgICAgICAgICAgICAgICAgIGFub3ZhLnNleC5wbG90LwogICAgICAgICAgICAgICAgICAgYW5vdmEuYWdlLnBsb3QpKQpgYGAKCiMjIyBGaWd1cmUgUzJDCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKbG1lX3Jlcy5kMTAgPC0gZGF0YV9uZXN0ZWQgJT4lIAogIG11dGF0ZShsbWUucmVzID0gcHVycnI6Om1hcChkYXRhLCB+IGxtZXJUZXN0OjpsbWVyKE5QWCB+IFRpbWUgKyBleHBvc3VyZSArICgxfHN0dWR5X2lkKSwgUkVNTCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbG1lNDo6bG1lckNvbnRyb2woY2hlY2suY29udi5zaW5ndWxhciA9ICJpZ25vcmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSAueCAlPiUgZHBseXI6OmZpbHRlcihUaW1lIT0iQWN1dGUiKSkpLAogICAgICAgICAjbG1lLnRpZHkgPSBwdXJycjo6bWFwKGxtZS5yZXMsIH4gYnJvb20ubWl4ZWQ6OnRpZHkoLikpLAogICAgICAgICBwb3N0aG9jLnRpbWUgPSBwdXJycjo6bWFwKGxtZS5yZXMsIH4gc3VtbWFyeShjb250cmFzdChlbW1lYW5zKC4sIH4gVGltZSksIG1ldGhvZCA9ICJwYWlyd2lzZSIpKSAlPiUgdGliYmxlKCkpIywKICAgICAgICAgI3Bvc3Rob2MudGltZV9leHBvc3VyZSA9IHB1cnJyOjptYXAobG1lLnJlcywgfiBzdW1tYXJ5KGNvbnRyYXN0KGVtbWVhbnMoLiwgfiBUaW1lICogZXhwb3N1cmUpLCBtZXRob2QgPSAicGFpcndpc2UiKSkgJT4lIHRpYmJsZSgpKQogICAgICAgICApCgpsbWVfcmVzLmQxMF9wYWRqIDwtIGxtZV9yZXMuZDEwICU+JSAKICB1bm5lc3QoY29scz0icG9zdGhvYy50aW1lIikgJT4lIAogIGZpbHRlcihjb250cmFzdD09IkQxMCAtIE0xMiIpICU+JSAKICAjZmlsdGVyKGNvbnRyYXN0PT0iQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIEFjdXRlIHByZXZpb3VzbHlfZXhwb3NlZCIpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShwLmFkaiA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIiksCiAgICAgICAgIEZEUiA9IGlmZWxzZShwLmFkaiA8PSAwLjAxLCBUUlVFLEZBTFNFKSkgJT4lIAogICMgICBkcGx5cjo6cmVuYW1lKGxvZ0ZDID0gZXN0aW1hdGUpICU+JSAKICBhcnJhbmdlKHAuYWRqKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CgphY3V0X2QxMF9saXN0IDwtIGxpc3QoIkFjdXRlIj1jKGxtZV9yZXNfcGFkaiAlPiUgZmlsdGVyKEZEUj09VFJVRSwgZXN0aW1hdGU+MSkgJT4lIHB1bGwoQXNzYXkpKSwKICAgICAgICAgICAgICAgICAgICAgICJEMTAiID0gYyhsbWVfcmVzLmQxMF9wYWRqICU+JSBmaWx0ZXIoRkRSPT1UUlVFLCBlc3RpbWF0ZT4xKSAlPiUgcHVsbChBc3NheSkpKQoKIyMgdmVubiBwbG90IHdpdGggb3ZlcmxhcHAgbnVtYmVycwoodmVubi5EQVAuYWN1dGUuZDEwIDwtIGdndmVubjo6Z2d2ZW5uKGFjdXRfZDEwX2xpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19wZXJjZW50YWdlID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsX2NvbG9yID0gYXMuY2hhcmFjdGVyKHRpbWUzX2NvbFtjKDEsMildKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Ryb2tlX3NpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V0X25hbWVfc2l6ZSA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dF9zaXplID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdXRvX3NjYWxlID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2VsZW1lbnRzID0gRikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIHBsb3QudGFnID0gZWxlbWVudF90ZXh0KHNpemU9NikpKQoKCmBgYAoKIyMjIEZpZ3VyZSBTMkQKYGBge3J9CihkMTBfbWFsYXJpYV92b2xjYW5vIDwtICBsbWVfcmVzLmQxMF9wYWRqICU+JSAKICAgYXJyYW5nZShwLmFkaiwgYWJzKGVzdGltYXRlKSkgJT4lIAogICBnZ3Bsb3QoYWVzKHg9ZXN0aW1hdGUsIHk9LWxvZzEwKHAuYWRqKSwgY29sb3I9RkRSKSkgKwogICBnZW9tX3BvaW50KGFscGhhPTAuNyxzaXplPS41LCBzaGFwZT0xNikgKwogICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YSA9IC4gJT4lIGZpbHRlcihGRFIgPT1UUlVFLCBhYnMoZXN0aW1hdGUpID4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IEFzc2F5KSwgY29sb3I9ImJsYWNrIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlICAgICAgICA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJib3RoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuYWxwaGE9LjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplPTEuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IDE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSB1bml0KDAuMiwgImxpbmVzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdncmV5NTAnCiAgICkgKwogICB0aGVtZV9taW5pbWFsKCkgKwogICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSwgbGluZXR5cGUgPSAiZG90dGVkIiwgc2l6ZSA9IC41KSArCiAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjAxKSwgbGluZXR5cGUgPSAiZG90dGVkIiwgc2l6ZSA9IC41KSArIAogICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoLTIuNSwtMS4wLDAuMCwxLjAsMi41LDUuMCksbGltaXRzID0gYygtMi41LDUpKSArCiAgIGxhYnMoeD0iRXN0aW1hdGVkIGRpZmZlcmVuY2UgKE5QWCkiLAogICAgICAgIHk9Ii1sb2cxMChhZGouIHAtdmFsdWUpIiwKICAgICAgICBzdWJ0aXRsZT0gIkQxMCBhZnRlciBkaXNlYXNlIHZzLiBjb252YWxlc2NlbmNlIiwKICAgICAgICBjYXB0aW9uPXBhc3RlMCgiREFQOiAiLGxtZV9yZXMuZDEwX3BhZGogJT4lIGZpbHRlcihGRFI9PVRSVUUpICU+JSBucm93KCksIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAiREFQIHVwOiAiLGxtZV9yZXMuZDEwX3BhZGogJT4lIGZpbHRlcihGRFI9PVRSVUUsZXN0aW1hdGU+MCkgJT4lIG5yb3coKSwiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICJEQVAgRkM+MTogIixsbWVfcmVzLmQxMF9wYWRqICU+JSBmaWx0ZXIoRkRSPT1UUlVFLGVzdGltYXRlPjEpICU+JSBucm93KCksIlxuIikpICsKICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NikpICsKICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYyh0aW1lM19jb2xbWzNdXSx0aW1lM19jb2xbWzJdXSkpKQpgYGAKCiMjIyBGaWd1cmUgUzJFCmBgYHtyfQooYWN1dGVfZDEwX2NvbXAgPC0gZGFwLnJlcyAlPiUgCiAgIHVuZ3JvdXAoKSAlPiUgCiAgIGFycmFuZ2UoLWxvZ0ZDKSAlPiUgCiAgIG11dGF0ZShyb3dfaWQ9cm93X251bWJlcigpKSAlPiUgCiAgIG11dGF0ZShBc3NheV9vcmRlcnMgPSBmYWN0b3IoYXMuZmFjdG9yKHJvd19pZCksIGxldmVscyA9IHJvd19pZCwgbGFiZWxzID0gQXNzYXkpLAogICAgICAgICAgQXNzYXlfb3JkZXJzID0gcm93X2lkKSAlPiUgCiAgIGxlZnRfam9pbihsbWVfcmVzLmQxMF9wYWRqLCBieT1jKCJBc3NheSIsIlVuaVByb3QiKSxzdWZmaXggPSBjKCIuYWN1dGUiLCIuZDEwIikpICU+JSAKICAgbXV0YXRlKGQgPSBpZmVsc2UoZXN0aW1hdGU+bG9nRkMsVCxGKSwKICAgICAgICAgIGRfZGJsID0gYWJzKGxvZ0ZDLWVzdGltYXRlKSkgJT4lCiAgIAogICBnZ3Bsb3QoYWVzKHg9QXNzYXlfb3JkZXJzKSkgKwogICBnZW9tX3NlZ21lbnQoZGF0YSA9IC4gJT4lIGZpbHRlcihwLmFkai5kMTA8PTAuMDEsIGVzdGltYXRlID4xKSwgCiAgICAgICAgICAgICAgICBhZXMoZ3JvdXA9QXNzYXksIHggPSBBc3NheV9vcmRlcnMsIHhlbmQgPSBBc3NheV9vcmRlcnMseWVuZCA9IGxvZ0ZDLCB5PWVzdGltYXRlLCBjb2xvcj1kKSwgbHdkPTAuMSkgKwogICBnZW9tX3BvaW50KGFlcyh5PWxvZ0ZDKSwgc2l6ZT0uMDUsIGFscGhhPTEsIGNvbG9yPXRpbWUzX2NvbFtbMV1dKSArCiAgIGdlb21fcG9pbnQoZGF0YSA9IC4gJT4lIGZpbHRlcihwLmFkai5kMTAgPD0wLjA1KSwgYWVzKHk9ZXN0aW1hdGUpLGNvbG9yPXRpbWUzX2NvbFtbMl1dLCBzaXplPS4wNSxhbHBoYT0xKSArCiAgIAogICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YSA9IC4gJT4lIGZpbHRlcihwLmFkai5kMTA8PTAuMDUsIGVzdGltYXRlID4xKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGQ9PVRSVUUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gZF9kYmwsbj0xMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBBc3NheSx5PWVzdGltYXRlLCBjb2xvcj1kKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JjZSAgICAgICAgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gICAgPSAiYm90aCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uc2VnbWVudC5sZW5ndGggPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplPTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gdW5pdCgwLjEsICJsaW5lcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9pbnQucGFkZGluZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnYmxhY2snKSArIAogICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIkZBTFNFIiA9ICJuYXZ5IiwiVFJVRSI9InJlZCIpLCBsYWJlbHM9YygibG93ZXIgYXQgRDEwIiwiaGlnaGVyIGF0IEQxMCIpKSArCiAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsbGluZXR5cGU9MywgY29sb3I9dGltZTNfY29sW1szXV0pICsKICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZD1jKC4xLDApLAogICAgICAgICAgICAgICAgICAgICAgdHJhbnMgPSAic3FydCIpICsgCiAgIGxhYnMoY29sb3IgPSBOVUxMLAogICAgICAgIHg9IlByb3RlaW5zIHJhbmtlZCBieSBlc3RpbWF0ZWQgZGlmZmVyZW5jZSAoTlBYKVxuYXQgYWN1dGUgbWFsYXJpYSIsCiAgICAgICAgeT0iRXN0aW1hdGVkIGRpZmZlcmVuY2UgKE5QWCkiKSArCiAgIHRoZW1lX21pbmltYWwoKSArCiAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSkgCikKYGBgCgoKIyMgU3VwcGxlbWVudGFyeSBGaWd1cmUgMyAKKipyZWxhdGVkIHRvIG1haW4gRmlndXJlIDEqKgoKIyMjIEZpZ3VyZSBTM0EKYGBge3J9CnJlcXVpcmUoY2x1c3RlclByb2ZpbGVyKQoKbGVuZ3RoKHVuaXF1ZShkYXRhJFVuaVByb3QpKSAjIyAxNDYzCgplbnRyZXpfdW5pcHJvdF9uYW1lX21hcHBpbmcgPC0gY2x1c3RlclByb2ZpbGVyOjpiaXRyKHVuaXF1ZShkYXRhLmxvbmckVW5pUHJvdCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyb21UeXBlPSJVTklQUk9UIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b1R5cGU9YygiU1lNQk9MIiwiRU5UUkVaSUQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBPcmdEYj0ib3JnLkhzLmVnLmRiIikgJT4lIAogIGRwbHlyOjpyZW5hbWUoVW5pUHJvdCA9IFVOSVBST1QsCiAgICAgICAgICAgICAgICBTeW1ib2wgPSBTWU1CT0wsCiAgICAgICAgICAgICAgICBFbnRyZXogPSBFTlRSRVpJRCkgCgpyYW5rc19lbnRyZXogPC0gZW50cmV6X3VuaXByb3RfbmFtZV9tYXBwaW5nICU+JSAKICBpbm5lcl9qb2luKGRhcC5yZXMgJT4lIHVuZ3JvdXAoKSAlPiUgZmlsdGVyKHAuYWRqPD0wLjAxKSwgYnk9IlVuaVByb3QiKSAlPiUKICBhcnJhbmdlKC1sb2dGQykgJT4lCiAgZHBseXI6OnNlbGVjdChFbnRyZXosIGxvZ0ZDKSAlPiUgZGVmcmFtZSgpCgojIyMgS0VHRwojIyBhbGwgZXhwbG9yZSBwcm90ZWlucwp1bml2ZXJzZS5wcm90ZWlucyA8LSBkYXRhLmxvbmcgJT4lIGRpc3RpbmN0KEFzc2F5LFVuaVByb3QpICU+JSBpbm5lcl9qb2luKGVudHJlel91bmlwcm90X25hbWVfbWFwcGluZyxieT0iVW5pUHJvdCIpCiMjIHByZXAgZW5yaWNoIGlucHV0CnNpZ19wcm90ZWluc19kZiA8LSBlbnRyZXpfdW5pcHJvdF9uYW1lX21hcHBpbmcgJT4lIAogIGlubmVyX2pvaW4oZGFwLnJlcyAlPiUgdW5ncm91cCgpLCBieT0iVW5pUHJvdCIpICU+JSBmaWx0ZXIocC5hZGogPD0gMC4wMSkgCgojIEZyb20gc2lnbmlmaWNhbnQgcmVzdWx0cywgd2Ugd2FudCB0byBmaWx0ZXIgb24gbG9nMmZvbGQgY2hhbmdlCnNpZ19wcm90ZWlucyA8LSBzaWdfcHJvdGVpbnNfZGYkbG9nRkMKIyBOYW1lIHRoZSB2ZWN0b3IKbmFtZXMoc2lnX3Byb3RlaW5zKSA8LSBzaWdfcHJvdGVpbnNfZGYkRW50cmV6CiMgb21pdCBOQSB2YWx1ZXMKc2lnX3Byb3RlaW5zIDwtIG5hLm9taXQoc2lnX3Byb3RlaW5zKQojIGZpbHRlciBvbiBtaW4gbG9nMmZvbGQgY2hhbmdlIChsb2cyRm9sZENoYW5nZSA+IDEpCnNpZ19wcm90ZWlucyA8LSBuYW1lcyhzaWdfcHJvdGVpbnMpW2FicyhzaWdfcHJvdGVpbnMpID4gMV0KCgpjcF9LRUdHLnJlcyA8LSBlbnJpY2hLRUdHKAogIHNpZ19wcm90ZWlucywKICBvcmdhbmlzbSA9ICJoc2EiLAogICNrZXlUeXBlID0gIlVOSVBST1QiLAogIHB2YWx1ZUN1dG9mZiA9IDEsCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgdW5pdmVyc2UgPSB1bml2ZXJzZS5wcm90ZWlucyRFbnRyZXosCiAgbWluR1NTaXplID0gMTAsIAogIG1heEdTU2l6ZSA9IDUwMCwKICBxdmFsdWVDdXRvZmYgPSAxLAogIHVzZV9pbnRlcm5hbF9kYXRhID0gRgopCgojZGF0YS5mcmFtZShjcF9LRUdHLnJlcykKCgooY3Aua2VnZy5hY3V0ZWZjMSA8LSBkYXRhLmZyYW1lKGNwX0tFR0cucmVzKSAlPiUKICAgIHNlcGFyYXRlKEdlbmVSYXRpbywgaW50bz1jKCJoaXQiLCJ0b3RhbCIpLHNlcD0iLyIscmVtb3ZlID0gRixjb252ZXJ0PVRSVUUpICU+JSAKICAgIGhlYWQoMTApICU+JSAKICAgIG11dGF0ZShyYXRpbyA9IGhpdC90b3RhbCkgJT4lIAogICAgCiAgICBnZ3Bsb3QoYWVzKHg9ZmN0X3Jlb3JkZXIoRGVzY3JpcHRpb24sIC1yYXRpbywuZGVzYyA9IFRSVUUpLCB5PXJhdGlvKSkgKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC4wNSkgKwogICAgZ2VvbV9wb2ludChhZXMoY29sb3I9LWxvZzEwKHAuYWRqdXN0KSkpICsjc2l6ZSA9IDMpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWw9aGl0KSxzaXplPTIsIG51ZGdlX3kgPSAuMDEpKwogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4wMiwwKSwgdHJhbnMgPSAicHNldWRvX2xvZyIpICsKICAgIHNjYWxlX3hfZGlzY3JldGUoZXhwYW5kID0gYygtMC4wMSwgMSkpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NiApLAogICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZ3VpZGVzKHNpemUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZT1UUlVFKSkgKwogICAgbGFicyh0aXRsZSA9ICJLRUdHXzIwMjFfSHVtYW4iLAogICAgICAgICB4PSBOVUxMLAogICAgICAgICB5ID0gInJhdGlvIFtwcm90ZWluL3RvdGFsXSIsCiAgICAgICAgIHNpemU9IlByb3RlaW5cbm92ZXJsYXBwIiwKICAgICAgICAgY29sb3I9ZXhwcmVzc2lvbigiLUxvZyJbMTBdKiIocC5hZGopIikpCiAgKQpgYGAKCiMjIyBGaWd1cmUgUzNCCmBgYHtyIEtFR0ctcGF0aHdheS13aWxjb3gsIGZpZy5jYXA9IktFR0ciLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZXF1aXJlKHBhdGh2aWV3KQoKc2lnX3Byb3RlaW5zX2RmIDwtIGVudHJlel91bmlwcm90X25hbWVfbWFwcGluZyAlPiUgCiAgaW5uZXJfam9pbihkYXAucmVzICU+JSB1bmdyb3VwKCksIGJ5PSJVbmlQcm90IikgJT4lIGZpbHRlcihwLmFkaiA8PSAwLjAxLCBhYnMobG9nRkMpPjEpIAoKCmxvZ0ZDIDwtIHNpZ19wcm90ZWluc19kZiRsb2dGQwpuYW1lcyhsb2dGQykgPC0gc2lnX3Byb3RlaW5zX2RmJEVudHJlegpwdi5vdXQgPC0gcGF0aHZpZXcoZ2VuZS5kYXRhID0gbG9nRkMsIAogICAgICAgICAgICAgICAgICAgcGF0aHdheS5pZCA9ICJoc2EwNDA2MCIsIAogICAgICAgICAgICAgICAgICAgc3BlY2llcyA9ICJoc2EiLCAKICAgICAgICAgICAgICAgICAgIGxpbWl0ID0gbGlzdChnZW5lPTUsIGNwZD0xKSwKKQoKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImhzYTA0MDYwLnBhdGh2aWV3LnBuZyIpCgpgYGAKCgojIEZpZ3VyZSAyCioqUG90ZW50aWFsIHNvdXJjZXMgYW5kIGZ1bmN0aW9uYWxpdGllcyBvZiBwbGFzbWEgcHJvdGVpbnMgZHVyaW5nIGFjdXRlIG1hbGFyaWEqKgoKIyMgRmlndXJlIDJBCgpgYGB7cn0Kc2VjcmV0b21lX2xvY2F0aW9uX2RhcCA8LSBkYXAucmVzICU+JSAKICBkcGx5cjo6ZmlsdGVyKEZEUj09VFJVRSkgJT4lCiAgYXJyYW5nZShkZXNjKGFicyhsb2dGQykpLGRlc2MocC5hZGopKSAlPiUgCiAgaW5uZXJfam9pbihocGFfMjQuMCwgYnk9YygiQXNzYXkiPSJnZW5lIiwiVW5pUHJvdCI9InVuaXByb3QiKSkgJT4lIAogIG11dGF0ZShzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMgPSBjYXNlX3doZW4oc2VjcmV0b21lX2xvY2F0aW9uPT0iTm90IHNlY3JldGVkIn4gcGFzdGUwKHNlY3JldG9tZV9sb2NhdGlvbiwiIC0gIixybmFfdGlzc3VlX3NwZWNpZmljaXR5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBzZWNyZXRvbWVfbG9jYXRpb24pKSAlPiUgCiAgZ3JvdXBfYnkoc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSAlPiUgCiAgY291bnQoc29ydCA9IFRSVUUpIAoKIyMgY2hhbmdlIG9yZGVyCnNlY3JldG9tZV9sb2NhdGlvbl9kYXAub3JkZXIgPC0gc2VjcmV0b21lX2xvY2F0aW9uX2RhcCAlPiUgcHVsbChzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpCnNlY3JldG9tZV9sb2NhdGlvbl9kYXAub3JkZXIgPC0gYygiU2VjcmV0ZWQgdG8gYmxvb2QiLCJJbnRyYWNlbGx1bGFyIGFuZCBtZW1icmFuZSIsIlNlY3JldGVkIGluIG90aGVyIHRpc3N1ZXMiLCJTZWNyZXRlZCB0byBleHRyYWNlbGx1bGFyIG1hdHJpeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgdG8gZGlnZXN0aXZlIHN5c3RlbSIsICJTZWNyZXRlZCBpbiBicmFpbiIsICJTZWNyZXRlZCAtIHVua25vd24gbG9jYXRpb24iLCAiU2VjcmV0ZWQgaW4gZmVtYWxlIHJlcHJvZHVjdGl2ZSBzeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIG1hbGUgcmVwcm9kdWN0aXZlIHN5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm90IHNlY3JldGVkIC0gVGlzc3VlIGVucmljaGVkIiwgIk5vdCBzZWNyZXRlZCAtIFRpc3N1ZSBlbmhhbmNlZCIsIk5vdCBzZWNyZXRlZCAtIEdyb3VwIGVucmljaGVkIiwgIk5vdCBzZWNyZXRlZCAtIExvdyB0aXNzdWUgc3BlY2lmaWNpdHkiKQoKIyMgcGxvdCBldmVyeXRoaW5nCihocGEucHJvdGVpbi5vcmlnaW4ub3ZlcnZpZXcgPC0gc2VjcmV0b21lX2xvY2F0aW9uX2RhcCAlPiUgCiAgICB1bmdyb3VwKCkgJT4lIAogICAgbXV0YXRlKHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyA9IGZhY3Rvcihhcy5mYWN0b3Ioc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSwgbGV2ZWxzPXJldihzZWNyZXRvbWVfbG9jYXRpb25fZGFwLm9yZGVyKSkpICU+JSAKICAgIGdncGxvdChhZXMoeD1zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMseT1uLGZpbGw9c2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSkgKwogICAgZ2VvbV9jb2wod2lkdGggPSAwLjUpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWw9biksc2l6ZT0yLCBudWRnZV95ID0gLS4yKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSJwc2V1ZG9fbG9nIixuYW1lID0gTlVMTCwgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LixsYWJlbHMgPSBOVUxMLGJyZWFrcyA9IE5VTEwsIG5hbWUgPSAiTnVtYmVyIG9mIERBUHMiKSwKICAgICAgICAgICAgICAgICAgICAgICAjZXhwYW5kPWMoMCwuMTUpCiAgICAgICAgICAgICAgICAgICAgICAgZXhwYW5kPWMoMCwwKQoKICAgICAgICAgICAgICAgICAgICAgICApICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NikpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlY19jb2xzLAogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gc2VjcmV0b21lX2xvY2F0aW9uX2RhcC5vcmRlcikgKwogICAgbGFicyhmaWxsPSJQcm90ZWluXG5vcmlnaW5cbmJ5IEhQQSIsCiAgICAgICAgIHg9TlVMTCkpCmBgYAoKYGBge3J9CnRlbXAuZGYgPC0gZGFwLnJlcyAlPiUgCiAgZHBseXI6OmZpbHRlcihGRFI9PVRSVUUpICU+JQogIGFycmFuZ2UoZGVzYyhhYnMobG9nRkMpKSxkZXNjKHAuYWRqKSkgJT4lIAogIGlubmVyX2pvaW4oaHBhXzI0LjAsIGJ5PWMoIkFzc2F5Ij0iZ2VuZSIsIlVuaVByb3QiPSJ1bmlwcm90IikpICU+JSAKICBtdXRhdGUoc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjID0gY2FzZV93aGVuKHNlY3JldG9tZV9sb2NhdGlvbj09Ik5vdCBzZWNyZXRlZCJ+IHBhc3RlMChzZWNyZXRvbWVfbG9jYXRpb24sIiAtICIscm5hX3Rpc3N1ZV9zcGVjaWZpY2l0eSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gc2VjcmV0b21lX2xvY2F0aW9uKSkKYGBgCgojIyBGaWd1cmUgMkIKYGBge3IgfQpkZjEgPC0gdGVtcC5kZiAlPiUgCiAgdHJhbnNtdXRlKEFzc2F5LCBsb2dGQywgcC5hZGosIGRpcmVjdGlvbixzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMsIHNlY3JldG9tZV9mdW5jdGlvbikgCgpkZjIgPC0gZGYxICU+JSAKICBncm91cF9ieShzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpICU+JSAKICBzdW1tYXJpc2UoYXRsYXNfbmFtZV9jb3VudCA9IG4oKSkgJT4lIAogIGxlZnRfam9pbigKICAgIGRmMSAlPiUgCiAgICAgIGdyb3VwX2J5KHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYywgc2VjcmV0b21lX2Z1bmN0aW9uLCBkaXJlY3Rpb24pICU+JSAKICAgICAgc3VtbWFyaXNlKGZ1bmN0aW9uX25hbWVfY291bnQgPSBuKCkpLAogICAgYnk9InNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyIpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBkZjEgJT4lIGdyb3VwX2J5KHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYywgc2VjcmV0b21lX2Z1bmN0aW9uLCBkaXJlY3Rpb24pICU+JSAKICAgICAgc3VtbWFyaXNlKG1lZGlhbl9sb2dGQyA9IG1lZGlhbihsb2dGQykpLAogICAgYnk9Yygic2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjIiwgInNlY3JldG9tZV9mdW5jdGlvbiIsImRpcmVjdGlvbiIpKQoKKGhwYS5mdW5jdGlvbi5idWJibGVwbG90IDwtIGRmMiAlPiUgCiAgICBmaWx0ZXIoIXNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyAlaW4lIGMoIk5VTEwiLCAiTkEiLCJubyBtYXBwaW5nIiksCiAgICAgICAgICAgIXNlY3JldG9tZV9mdW5jdGlvbiAlaW4lIGMoIk5VTEwiKSkgJT4lIAogICAgbXV0YXRlKHNlY3JldG9tZV9mdW5jdGlvbiA9IGNhc2Vfd2hlbihpcy5uYShzZWNyZXRvbWVfZnVuY3Rpb24pIH4gIk5vIHNlY3JldG9tZSBmdW5jdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gc2VjcmV0b21lX2Z1bmN0aW9uKSkgJT4lIAogICAgbXV0YXRlKHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyA9IGZhY3Rvcihhcy5mYWN0b3Ioc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHM9cmV2KHNlY3JldG9tZV9sb2NhdGlvbl9kYXAub3JkZXIpKSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PW1lZGlhbl9sb2dGQywKICAgICAgICAgICAgICAgeT0gZmN0X3Jlb3JkZXIyKHNlY3JldG9tZV9mdW5jdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdGxhc19uYW1lX2NvdW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb25fbmFtZV9jb3VudCwuZGVzYyA9IEYpKSkgKwogICAgZ2VvbV9wb2ludChhZXMoc2l6ZT1mdW5jdGlvbl9uYW1lX2NvdW50LCBjb2xvcj1zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpLCBzaG93LmxlZ2VuZCA9IFQpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsbGluZXR5cGU9MSkgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZ1bmN0aW9uX25hbWVfY291bnQpLAogICAgICAgICAgICAgIHNpemU9MiwgY29sb3I9ImdyZXkyMCIsc2hvdy5sZWdlbmQgPSBGLCBwYXJzZSA9IEYpICsKICAgIGxhYnMoeD0ibWVkaWFuIGVzdGltYXRlZCBkaWZmZXJlbmNlIChOUFgpIiwKICAgICAgICAgeT1OVUxMLAogICAgICAgICB0aXRsZSA9ICJOdW1iZXIgREFQcyBwZXIgSFBBIGZ1bmN0aW9uIiwKICAgICAgICAgc2l6ZT0iTnVtYmVyIG9mIHByb3RlaW5zIiwKICAgICAgICAgY2FwdGlvbj0iU2l6ZTogbnVtYmVyIG9mIHByb3RlaW5zIiwKICAgICAgICAgY29sb3IgPSAiSFBBIHNvdXJjZSIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjX2NvbHMsIGxpbWl0cyA9IHNlY3JldG9tZV9sb2NhdGlvbl9kYXAub3JkZXIpICsKICAgIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJwc2V1ZG9fbG9nIikgKwogICAgc2NhbGVfeV9kaXNjcmV0ZShleHBhbmQgPSBjKDAsMSkpKwogICAgZ3VpZGVzKHNpemUgPSAibm9uZSIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBzY2FsZV9zaXplKHJhbmdlPWMoMyw2KSkgKwogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYpKQopCmBgYAoKCiMjIEZpZ3VyZSAyQwpgYGB7ciBEQVAtaHBhLWZ1bmN0aW9ufQooYWN1dGVfbWFsYXJpYV9ocGFfc291cmNlIDwtIHRlbXAuZGYgJT4lIAogICAgcmlnaHRfam9pbih0b3AyNSAlPiUgdHJhbnNtdXRlKEFzc2F5LGxvZ0ZDKSkgJT4lIAogICAgCiAgICBnZ3Bsb3QoYWVzKHg9ZmN0X3Jlb3JkZXIoQXNzYXksbG9nRkMpLCB5PWxvZ0ZDLCBjb2xvcj1zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpKSArCiAgICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gVFJVRSxzaXplPTEpICsKICAgIGdlb21fY29sKHdpZHRoID0gLjA1LHNob3cubGVnZW5kID0gRikgKwogICAgc2NhbGVfeV9jb250aW51b3VzKHNlYy5heGlzID0gc2VjX2F4aXMofi4sbGFiZWxzID0gTlVMTCxicmVha3MgPSBOVUxMLCBuYW1lID0gIlRvcDI1IERBUCIpKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyhjb2xvcj0iSFBBIHNvdXJjZSIsCiAgICAgICAgIHg9IiIsCiAgICAgICAgIHk9IkVzdGltYXRlZCBkaWZmZXJlbmNlIChOUFgpIiwKICAgICAgICAgdGl0bGUgPSAiUHJvdGVpbiBzb3VyY2UgYWNjb3JkaW5nIHRvIEh1bWFuIFByb3RlaW4gQXRsYXMiKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlY19jb2xzLAogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cz1zZWNyZXRvbWVfbG9jYXRpb25fZGFwLm9yZGVyKSkKYGBgCgoKIyMgU3VwcGxlbWVudGFyeSBGaWd1cmUgNCAKKipyZWxhdGVkIHRvIG1haW4gRmlndXJlIDIqKgoKIyMjIEZpZ3VyZSBTNEEKYGBge3J9Cm1hbGFyaWEuZGFwcy5ocGEyMyA8LSBkYXAucmVzICU+JSAKICBhcnJhbmdlKGRlc2MoYWJzKGxvZ0ZDKSksZGVzYyhwLmFkaikpICU+JSAKICBmaWx0ZXIocC5hZGo8PTAuMDEpICU+JSAKICBhcnJhbmdlKC1sb2dGQykgJT4lIAogIGxlZnRfam9pbihocGFfMjQuMCxieT1jKCJVbmlQcm90IiA9ICJ1bmlwcm90IikpICU+JSAKICB1bmdyb3VwKCkKCiMjIGFidW5kYW50IHByb3RlaW5zIGluIGFjdXRlIG1hbGFyaWEgcGxhc21hLCBub3QgaW1tdW5lIGNlbGwgc3BlY2lmaWMgbm9yIHByZWRpY3RlZCB0byBiZSBzZWNyZXRlZAojIyA9PiB0aXNzdWUgbGVha2FnZT8/Cm1hbGFyaWEudGlzc3VlLmxlYWthZ2UgPC0gbWFsYXJpYS5kYXBzLmhwYTIzICU+JSAKICBmaWx0ZXIoaXMubmEocm5hX2Jsb29kX2NlbGxfc3BlY2lmaWNpdHkpIHwgCiAgICAgICAgICAgcm5hX2Jsb29kX2NlbGxfc3BlY2lmaWNpdHk9PSJOb3QgZGV0ZWN0ZWQgaW4gaW1tdW5lIGNlbGxzIiwgCiAgICAgICAgIHJuYV90aXNzdWVfc3BlY2lmaWNpdHkgJWluJSBjKCJUaXNzdWUgZW5yaWNoZWQiKSwjLCJHcm91cCBlbnJpY2hlZCIsIlRpc3N1ZSBlbmhhbmNlZCIpLAogICAgICAgICBzZWNyZXRvbWVfbG9jYXRpb24gPT0iTm90IHNlY3JldGVkIiwKICAgICAgICAgbG9nRkMgPjApIy41KQoKc2VjcmV0b21lLmxvY2F0aW9uLm9yZGVyIDwtIGMoIlNlY3JldGVkIHRvIGJsb29kIiwiSW50cmFjZWxsdWxhciBhbmQgbWVtYnJhbmUiLCJTZWNyZXRlZCBpbiBvdGhlciB0aXNzdWVzIiwiU2VjcmV0ZWQgdG8gZXh0cmFjZWxsdWxhciBtYXRyaXgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIHRvIGRpZ2VzdGl2ZSBzeXN0ZW0iLCAiU2VjcmV0ZWQgaW4gYnJhaW4iLCAiU2VjcmV0ZWQgLSB1bmtub3duIGxvY2F0aW9uIiwgIlNlY3JldGVkIGluIGZlbWFsZSByZXByb2R1Y3RpdmUgc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCBpbiBtYWxlIHJlcHJvZHVjdGl2ZSBzeXN0ZW0iLCJOb3Qgc2VjcmV0ZWQiKQpzZWNyZXRvbWUuZnVuLmNvdW50IDwtIG1hbGFyaWEuZGFwcy5ocGEyMyAlPiUgZ3JvdXBfYnkoc2VjcmV0b21lX2Z1bmN0aW9uKSAlPiUgY291bnQoKSAlPiUgYXJyYW5nZSgtbikgJT4lIHB1bGwoc2VjcmV0b21lX2Z1bmN0aW9uKQoKZGYgPC0gbWFsYXJpYS5kYXBzLmhwYTIzICU+JSAKICBmaWx0ZXIobG9nRkM+PTApICU+JSAKICB0cmFuc211dGUoQXNzYXksCiAgICAgICAgICAgIGRpcmVjdGlvbiwKICAgICAgICAgICAgc2VjcmV0b21lX2xvY2F0aW9uID0gZmFjdG9yKHNlY3JldG9tZV9sb2NhdGlvbiwgbGV2ZWxzPSBzZWNyZXRvbWUubG9jYXRpb24ub3JkZXIpLAogICAgICAgICAgICBzZWNyZXRvbWVfZnVuY3Rpb24gPSBmYWN0b3Ioc2VjcmV0b21lX2Z1bmN0aW9uLCBsZXZlbHMgPSBzZWNyZXRvbWUuZnVuLmNvdW50KSwKICAgICAgICAgICAgcm5hX2Jsb29kX2NlbGxfc3BlY2lmaWNpdHksCiAgICAgICAgICAgIHJuYV90aXNzdWVfc3BlY2lmaWNpdHkgPSBmYWN0b3Iocm5hX3Rpc3N1ZV9zcGVjaWZpY2l0eSwgbGV2ZWxzID0gYygiVGlzc3VlIGVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcm91cCBlbnJpY2hlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGlzc3VlIGVuaGFuY2VkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb3cgdGlzc3VlIHNwZWNpZmljaXR5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3QgZGV0ZWN0ZWQiKSksCiAgICAgICAgICAgIHRpc3N1ZV9lbnJpY2hlZCA9IGZhY3RvcihjYXNlX3doZW4ocm5hX2Jsb29kX2NlbGxfc3BlY2lmaWNpdHk9PSJOb3QgZGV0ZWN0ZWQgaW4gaW1tdW5lIGNlbGxzIiAmIHJuYV90aXNzdWVfc3BlY2lmaWNpdHkgPT0gIlRpc3N1ZSBlbnJpY2hlZCIgJiBzZWNyZXRvbWVfbG9jYXRpb24gPT0iTm90IHNlY3JldGVkIiAmIGRpcmVjdGlvbiA9PSAidXAiIH4iMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSAiMCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1jKCIxIiwiMCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCIxIj0iVGlzc3VlIHNwZWNpZmljIGFuZCBub3Qgc2VjcmV0ZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjAiPSJMZXNzIHRpc3N1ZSBzcGVjaWZpYyIpCiAgICAgICAgICAgICkpCmBgYAoKCmBgYHtyfQooZGFwLm9yaWdpbi53LnRsIDwtIGRmICU+JQogICAgZ2dwbG90KGFlcyhheGlzMSA9IHNlY3JldG9tZV9sb2NhdGlvbiwKICAgICAgICAgICAgICAgYXhpczIgPSBzZWNyZXRvbWVfZnVuY3Rpb24sCiAgICAgICAgICAgICAgIGF4aXMzID0gcm5hX3Rpc3N1ZV9zcGVjaWZpY2l0eSwKICAgICAgICAgICAgICAgYXhpczQgPSB0aXNzdWVfZW5yaWNoZWQKICAgICkpICsKICAgIGdlb21fYWxsdXZpdW0oYWVzKGZpbGwgPSBzZWNyZXRvbWVfbG9jYXRpb24pLHdpZHRoID0gMS8xMixnZW9tID0gImZsb3ciLCBsb2RlLmd1aWRhbmNlID0gImZvcndhcmQiLCkgKwogICAgZ2VvbV9zdHJhdHVtKGFlcyhmaWxsPXNlY3JldG9tZV9sb2NhdGlvbiksd2lkdGggPSAxLzEyKSArCiAgICBnZ2ZpdHRleHQ6Omdlb21fZml0X3RleHQoc3RhdCA9ICJzdHJhdHVtIiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChzdHJhdHVtKSksbWluLnNpemUgPSAxLCBzaG93LmxlZ2VuZCA9IEYpICsKICAgIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiU2VjcmV0b21lXG5sb2NhdGlvbiIsIlNlY3JldG9tZVxuZnVuY3Rpb24iLCAiVGlzc3VlIHNwZWNpZmljaXR5XG4oYmFzZWQgb24gZ2VuZSBleHByZXNzaW9uKSIsIlRpc3N1ZSBzcGVjaWZpY2l0eVxuKG92ZXJhbGwpIiksIGV4cGFuZCA9IGMoLjIsIC4wNSkpICsKICAgIHRoZW1lX2J3KCkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjKHNlY3JldG9tZV9sb2NhdGlvbl9jb2xzLCJOQSI9InJlZCIsIlNQRUMiPSJ3aGl0ZSIpKSArCiAgICBsYWJzKHRpdGxlID0gIkFidW5kYW50IHByb3RlaW5zIGluIGJsb29kIGR1cmluZyBhY3V0ZSBtYWxhcmlhIiwKICAgICAgICAgeT0gIk51bWJlciBvZiBwcm90ZWlucyIpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siLCBzaXplPTAuNSwgZmlsbD1OQSksCiAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3Qoc2l6ZSA9IDAuMiwgY29sb3VyID0gImdyZXkiKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmBgYAoKIyMjIEZpZ3VyZSBTNEIKYGBge3J9CihhbGx1dmlhbF9wcm90ZWlub3JpZ2luIDwtIGRmICU+JQogICBnZ3Bsb3QoYWVzKGF4aXMxID0gc2VjcmV0b21lX2xvY2F0aW9uLAogICAgICAgICAgICAgIGF4aXMzID0gcm5hX3Rpc3N1ZV9zcGVjaWZpY2l0eSwKICAgICAgICAgICAgICBheGlzNCA9IHRpc3N1ZV9lbnJpY2hlZAogICApKSArCiAgIGdlb21fYWxsdXZpdW0oYWVzKGZpbGwgPSB0aXNzdWVfZW5yaWNoZWQpLHdpZHRoID0gMS8xMixnZW9tID0gImZsb3ciLCBsb2RlLmd1aWRhbmNlID0gImZvcndhcmQiLCkgKwogICBnZW9tX3N0cmF0dW0oYWVzKGZpbGw9c2VjcmV0b21lX2xvY2F0aW9uKSx3aWR0aCA9IDEvMTIpICsKICAgZ2dmaXR0ZXh0OjpnZW9tX2ZpdF90ZXh0KHN0YXQgPSAic3RyYXR1bSIsIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoc3RyYXR1bSkpLG1pbi5zaXplID0gMSwgc2hvdy5sZWdlbmQgPSBGKSArCiAgIAogICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoIlNlY3JldG9tZVxubG9jYXRpb24iLCMiU2VjcmV0b21lXG5mdW5jdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRpc3N1ZSBzcGVjaWZpY2l0eVxuKGJhc2VkIG9uIGdlbmUgZXhwcmVzc2lvbikiLCJUaXNzdWUgc3BlY2lmaWNpdHlcbihvdmVyYWxsKSIpLCBleHBhbmQgPSBjKC4yLCAuMDUpKSArCiAgIHRoZW1lX2J3KCkgKwogICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGMoIlRpc3N1ZSBzcGVjaWZpYyBhbmQgbm90IHNlY3JldGVkIj0icmVkIiwiTGVzcyB0aXNzdWUgc3BlY2lmaWMiPSJncmV5OTAiKSkgKwogICBsYWJzKHRpdGxlID0gIlBvdGVudGlhbCB0aXNzdWUgbGVha2FnZSBwcm90ZWlucyBpbiBibG9vZCBkdXJpbmcgYWN1dGUgbWFsYXJpYSIsCiAgICAgICAgeT0gIk51bWJlciBvZiBwcm90ZWlucyIpICsKICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIsIHNpemU9MC41LCBmaWxsPU5BKSwKICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KHNpemUgPSAwLjIsIGNvbG91ciA9ICJncmV5IiksCiAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCgptYWxhcmlhLnRpc3N1ZS5sZWFrYWdlIDwtIGRmICU+JSBmaWx0ZXIodGlzc3VlX2VucmljaGVkPT0iVGlzc3VlIHNwZWNpZmljIGFuZCBub3Qgc2VjcmV0ZWQiKSAlPiUgcHVsbChBc3NheSkKYGBgCgojIyMgRmlndXJlIFM0QwpgYGB7cn0KIyMjIHRpc3N1ZSBleHByZXNzaW9uwqgKbWF0IDwtIGhwYS50aXNzdWUgJT4lIAogIGZpbHRlcihnZW5lX25hbWUgJWluJSBjKG1hbGFyaWEudGlzc3VlLmxlYWthZ2UpKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRpc3N1ZSwgdmFsdWVzX2Zyb20gPSBuX3RwbSwgdmFsdWVzX2ZuID0gbWVkaWFuKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtZ2VuZSkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygiZ2VuZV9uYW1lIikKCm1hdDEgPC0gbWF0ICU+JSAKICB0KCkgJT4lIAogIHNjYWxlKCkgJT4lIAogIHNjYWxlczo6cmVzY2FsZSh0bz1jKDAsMSkpICU+JSAKICB0KCkgCgooaG0udGlzc3VlLmxlYWthZ2UgPC0gbWF0MSAlPiUgCiAgICB0KCkgJT4lIAogICAgSGVhdG1hcChyb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSAgZ3Bhcihmb250c2l6ZT00KSwKICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gVCwKICAgICAgICAgICAgbmFtZT0ic2NhbGVkXG5uVFBNIiwKICAgICAgICAgICAgY29sdW1uX3RpdGxlID0gIkhpZ2ggYWJ1bmRhbnQgcGxhc21hIHByb3RlaW5zXG4gJ1Rpc3N1ZSBzcGVjaWZpYyBhbmQgbm90IHNlY3JldGVkJyIsCiAgICAgICAgICAgIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICAgIGNvbCA9IGNpcmNsaXplOjpjb2xvclJhbXAyKGMobWluKG1hdDEpLG1heChtYXQxKSksIGMoIndoaXRlIiwicmVkIikpLAogICAgICAgICAgICBjb2x1bW5fZGVuZF9oZWlnaHQgPSB1bml0KDUsIm1tIiksCiAgICAgICAgICAgIHJvd19kZW5kX3dpZHRoID0gdW5pdCg1LCJtbSIpLAogICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCgyMCwgIm1tIikpKQopCmBgYAoKIyMjIEZpZ3VyZSBTNEQKYGBge3J9Cih0aXNzdWUubGVha2FnZS52aW9saW5lIDwtIGRhdGEubG9uZyAlPiUgCiAgIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlICU+JSBkcGx5cjo6c2VsZWN0KERBaWQsVGltZSxzYW1wbGVfaWQsc3R1ZHlfaWQpLAogICAgICAgICAgICAgIGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgIGRwbHlyOjpmaWx0ZXIoQXNzYXkgJWluJSBjKG1hbGFyaWEudGlzc3VlLmxlYWthZ2UpLCMiREVGQTEiLCJERUZBMUIiKSwKICAgICAgICAgICAgICAgICBUaW1lIT0iRDEwIikgJT4lIAogICBtdXRhdGUoQXNzYXkgPSBmYWN0b3IoQXNzYXksIGxldmVscyA9IGMobWFsYXJpYS50aXNzdWUubGVha2FnZSkpKSAlPiUgIywiREVGQTEiLCJERUZBMUIiKSkpICU+JSAKICAgIGdncGxvdChhZXMoeD1UaW1lLCB5PU5QWCwgY29sb3I9VGltZSxmaWxsPVRpbWUpKSArIAogICAgZ2VvbV9saW5lKGFlcyhncm91cD1zdHVkeV9pZCksIGNvbG9yPSJncmV5IixhbHBoYT0uNixzaXplPS4yKSsKICAgIGdlb21fdmlvbGluKHRyaW0gPSBGLGFscGhhPS4yLGx3ZD0uMjUpICsKICAgIGdlb21fYm94cGxvdChhbHBoYT0xLHdpZHRoPTAuMjUsY29sb3I9ImJsYWNrIixvdXRsaWVyLnNpemUgPSAwLjUsIGZhdHRlbiA9IDEsbHdkPS4yNSxzaG93LmxlZ2VuZCA9IEYpICsKICAgIGZhY2V0X3dyYXAofkFzc2F5LG5jb2wgPSA5LHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh4PSIiKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwjIGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9dGltZTNfY29sKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9dGltZTNfY29sKSkKYGBgCgogUmV2aXNpb24gZXh0cmEKCmBgYHtyfQpkZiA8LSAgZGF0YS5sb25nICU+JSAKICAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUgJT4lIGRwbHlyOjpzZWxlY3QoREFpZCxUaW1lLHNhbXBsZV9pZCxzdHVkeV9pZCksCiAgICAgICAgICAgICAgYnk9InNhbXBsZV9pZCIpICU+JSAKICBmaWx0ZXIoQXNzYXklaW4lIGMoIkFHWFQiLCJIQU8xIiksCiAgICAgICAgIFRpbWU9PSJBY3V0ZSIpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBjbGluY2hlbV9zdHVkeV9wYXRzX2FjdXRlLndpZGUgJT4lIHRyYW5zbXV0ZShzdHVkeV9pZCwgcF9hc2F0LCBwX2FsYXQpCiAgKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImNsaW5jaGVtIiwgdmFsdWVzX3RvID0gImNsaW5jaGVtX3ZhbCIsY29scyA9IHBfYXNhdDpwX2FsYXQpCgojY29yLnRlc3QucmVzIDwtIHRpZHkoY29yLnRlc3QoZGYkYENEMTkrIENEMjArQkFGRi1SYCxkZiRUTkZTRjEzQixtZXRob2QgPSAic3BlYXJtYW4iKSkKZGYgJT4lIAogIHRyYW5zbXV0ZShzYW1wbGVfaWQsIEFzc2F5LE5QWCxjbGluY2hlbSxjbGluY2hlbV92YWwpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQXNzYXksIHZhbHVlc19mcm9tID0gTlBYKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY2xpbmNoZW0sIHZhbHVlc19mcm9tID0gY2xpbmNoZW1fdmFsKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGVfaWQiKSAlPiUgCiAgY29ycmVsYXRpb24oKSAlPiUgCiAgdGliYmxlKCkgJT4lIAogIGZpbHRlcihQYXJhbWV0ZXIxIT1QYXJhbWV0ZXIyLAogICAgICAgICBQYXJhbWV0ZXIyIT0iSEFPMSIpCgpkZiAlPiUgCiAgZ2dwbG90KGFlcyh4PU5QWCx5PWNsaW5jaGVtX3ZhbCkpICsKICAjZ2VvbV9wb2ludChzaGFwZT0xNiwgc2l6ZT0uNSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsKICBmYWNldF9ncmlkKEFzc2F5fmNsaW5jaGVtKQogICNzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWVuZGVtaWMyX2NvbCkrCiAgI2Fubm90YXRlKCJ0ZXh0IiwKICAjICAgICAgICAgeD0yLAogICMgICAgICAgICB5PTc1MDAsCiAgIyAgICAgICAgIHNpemU9MS41LAogICMgICAgICAgICBsYWJlbD1wYXN0ZSgiXG5yaG86ICIscm91bmQoY29yLnRlc3QucmVzJGVzdGltYXRlLDIpLAogICMgICAgICAgICAgICAgICAgICAgICAiXG5wLXZhbHVlOiIsc2NhbGVzOjpzY2llbnRpZmljX2Zvcm1hdCgpKGNvci50ZXN0LnJlcyRwLnZhbHVlKSkpICsKICAjbGFicyh4PSJUTkZTRjEzQiBbTlBYXVxuYXQgQWN1dGUiLAogICAjICAgIHk9IkNEMTkrIENEMjArQkFGRi1SIFtNRkldXG5hdCBBY3V0ZSIsCiAgICAjICAgY29sb3I9TlVMTCkpCgpsaWJyYXJ5KHNlZSkKZGYgJT4lIAogIHRyYW5zbXV0ZShzYW1wbGVfaWQsIEFzc2F5LE5QWCxjbGluY2hlbSxjbGluY2hlbV92YWwpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQXNzYXksIHZhbHVlc19mcm9tID0gTlBYKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY2xpbmNoZW0sIHZhbHVlc19mcm9tID0gY2xpbmNoZW1fdmFsKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGVfaWQiKSAlPiUgCiAgY29ycmVsYXRpb24oKSAlPiUgCiAgc3VtbWFyeSgpICU+JSAKICBwbG90KCkgKwoKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQpgYGAKCgojIyBTdXBwbGVtZW50YXJ5IEZpZ3VyZSA1CioqcmVsYXRlZCB0byBtYWluIEZpZ3VyZSAyKioKIyMjIEZpZ3VyZSBTNUEtRApgYGB7cn0KaT0iU2VjcmV0ZWQgdG8gYmxvb2QiCmFjdXRlX21hbGFyaWFfaHBhX2Z1bmN0aW9uX2ZhY2V0Lmxpc3QgPC0gbGlzdCgpCmZvcihpIGluIGMoIlNlY3JldGVkIHRvIGJsb29kIiwiSW50cmFjZWxsdWxhciBhbmQgbWVtYnJhbmUiLCJTZWNyZXRlZCBpbiBvdGhlciB0aXNzdWVzIiwiU2VjcmV0ZWQgdG8gZXh0cmFjZWxsdWxhciBtYXRyaXgiLCJTZWNyZXRlZCB0byBkaWdlc3RpdmUgc3lzdGVtIiwiU2VjcmV0ZWQgaW4gYnJhaW4iLCJTZWNyZXRlZCAtIHVua25vd24gbG9jYXRpb24iKSl7CiAgCiAgKGFjdXRlX21hbGFyaWFfaHBhX2Z1bmN0aW9uX2ZhY2V0Lmxpc3RbW2ldXSA8LSAKICAgICBkYXAucmVzICU+JSAKICAgICBkcGx5cjo6ZmlsdGVyKEZEUj09VFJVRSwKICAgICAgICAgICAgICAgICAgIGFicyhsb2dGQyk+MCkgJT4lCiAgICAgaW5uZXJfam9pbihocGFfMjQuMCxieT1jKCJBc3NheSI9ImdlbmUiKSkgJT4lIAogICAgIGRwbHlyOjpmaWx0ZXIoc2VjcmV0b21lX2xvY2F0aW9uID09IGksIAogICAgICAgICAgICAgICAgICAgIXNlY3JldG9tZV9mdW5jdGlvbiAlaW4lIGMoTkEsIk5VTEwiLCJOb3Qgc2VjcmV0ZWQiKQogICAgICkgJT4lIAogICAgICAgdW5ncm91cCgpICU+JSAKICAgICAgIG11dGF0ZShzZWNyZXRvbWVfZnVuY3Rpb24gPSBmYWN0b3Ioc2VjcmV0b21lX2Z1bmN0aW9uKSklPiUgCiAgICAgICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmVvcmRlcjIoQXNzYXksIHNlY3JldG9tZV9mdW5jdGlvbiwgLWxvZ0ZDKSwKICAgICAgICAgICAgICAgICAgeT1sb2dGQywgY29sb3IgPSBzZWNyZXRvbWVfbG9jYXRpb24pKSArCiAgICAgICBnZW9tX3BvaW50KHNpemU9MSwgc2hvdy5sZWdlbmQgPSBGKSArIAogICAgICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj0gbG9nRkMgLSAxLjk2KlNFLCMgMS45NipTRSA9Y29uZi5sb3cKICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9bG9nRkMgKyAxLjk2KlNFLCNjb25mLmhpZ2gsCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1zZWNyZXRvbWVfbG9jYXRpb24pLAogICAgICAgICAgICAgICAgICAgICBzaXplPS4yNSwgICAgCiAgICAgICAgICAgICAgICAgICAgIHdpZHRoPS4yLAogICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSguOSksCiAgICAgICAgICAgICAgICAgICAgIGFscGhhPS41KSArCiAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0yLCBhbHBoYT0uNCkgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzZWNyZXRvbWVfbG9jYXRpb25fY29scykgKwogICAgICAgY29vcmRfZmxpcCgpICsKICAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKHNlY3JldG9tZV9sb2NhdGlvbiksIAogICAgICAgICAgICAgICAgICByb3dzID0gdmFycyhzZWNyZXRvbWVfZnVuY3Rpb24pLCBzY2FsZXMgPSAiZnJlZSIsIHNwYWNlID0gImZyZWVfeSIsZHJvcCA9IEYpICsKICAgICAgIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsc2l6ZT0zLjUpLAogICAgICAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gImluc2lkZSIsCiAgICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMpLAogICAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTUpLAogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSksCiAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTUpLAogICAgICAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemU9NSksCiAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gLjUpLAogICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9saW5lKGxpbmV3aWR0aCA9IC41KSwKICAgICAgICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgICAgIGxhYnMoeD0iIiwKICAgICAgICAgICAgeT0iRXN0aW1hdGVkIGRpZmZlcmVuY2UgKE5QWCkgd2l0aCA5NSUgQ0kiKSArCiAgICAgICBleHBhbmRfbGltaXRzKHkgPSBjKC0xLDEpKQogICkKfQpgYGAKCgojIyMgZGVsdGEgTlBYIAotIG5lZWRlZCBmb3IgaGVhdG1hcCBhbm5vdGF0aW9uIGFuZCAgbGF0ZXIgb24gY2x1c3RlcmluZwpgYGB7cn0KZGZfNF9mYyA8LSBkYXRhLndpZGUgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlICU+JSBkcGx5cjo6c2VsZWN0KERBaWQsc3R1ZHlfaWQsIHNhbXBsZV9pZCwgVGltZSksYnk9InNhbXBsZV9pZCIpICU+JSAKICBkcGx5cjo6ZmlsdGVyKFRpbWUhPSJEMTAiKSAlPiUgCiAgZHBseXI6OnNlbGVjdChEQWlkLHN0dWR5X2lkLCBzYW1wbGVfaWQsIFRpbWUsIGV2ZXJ5dGhpbmcoKSkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gNTpuY29sKC4pLCBuYW1lc190byA9ICJBc3NheSIsIHZhbHVlc190byA9ICJOUFgiKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtREFpZCwtc2FtcGxlX2lkKSAlPiUgCiAgcGl2b3Rfd2lkZXIodmFsdWVzX2Zyb20gPSAiTlBYIiwgbmFtZXNfZnJvbSA9ICJUaW1lIikKCgpNMTJfbWVkaWFuX00xMiA8LSBkZl80X2ZjICU+JSAKICBncm91cF9ieShBc3NheSkgJT4lIAogIHN1bW1hcmlzZShtMTJfbWVkaWFuID0gbWVkaWFuKE0xMixuYS5ybSA9IFRSVUUpKSAKCmZjX292ZXJfbWVkaWFuX00xMiA8LSBkZl80X2ZjICU+JSAKICBpbm5lcl9qb2luKE0xMl9tZWRpYW5fTTEyLCBieT0iQXNzYXkiKSAlPiUgCiAgZ3JvdXBfYnkoQXNzYXkpICU+JSAKICBtdXRhdGUobG9nMkZDX21lZGlhbk0xMiA9IEFjdXRlLW0xMl9tZWRpYW4pICU+JSAKICBkcGx5cjo6c2VsZWN0KC1NMTIpICU+JSAKICBuYS5vbWl0KCkgJT4lIAogIGRwbHlyOjpyZW5hbWUoZE5QWCA9IGxvZzJGQ19tZWRpYW5NMTIpIAoKI2ZjX292ZXJfbWVkaWFuX00xMiAlPiUgc2F2ZVJEUygiLi4vZGF0YS9kYXRhX2NsZWFuLzIwMjMwNDI2X0V4cGxvcmUxNTM2X2ZjX292ZXJfbWVkaWFuX20xMl90aWR5X2xvbmcucmRzIikKZmNfb3Zlcl9tZWRpYW5fTTEyICU+JSBoZWFkKCkKYGBgCgoKCiMgRmlndXJlIDMgCioqU2luZ2xlLWNlbGwgdHJhbnNjcmlwdG9taWNzIG9mIFBCTUNzIGR1cmluZyBhY3V0ZSBtYWxhcmlhKioKCmBgYHtyIHBjYS1kYXRhLXJoYXBzb2R5aGlnaGxpZ2h0fQpkZiA8LSBkYXRhLndpZGUgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlICU+JSAKICAgICAgICAgICAgICAgdHJhbnNtdXRlKHNhbXBsZV9pZCksCiAgICAgICAgICAgICBieT0ic2FtcGxlX2lkIikgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic2FtcGxlX2lkIikKCiMjIFBDIGNhbGN1bGF0aW9uCnBjYVJlcyA8LSBzdGF0czo6cHJjb21wKGRmLGNlbnRlciA9IFRSVUUsIHNjYWxlLiA9IFRSVUUpCnZhckV4cCA8LSByb3VuZChwY2FSZXMkc2Rldl4yIC8gc3VtKHBjYVJlcyRzZGV2XjIpICogMTAwKQpwY2FERiA8LSBkYXRhLmZyYW1lKFBDMSA9IHBjYVJlcyR4WywgMV0sCiAgICAgICAgICAgICAgICAgICAgUEMyID0gcGNhUmVzJHhbLCAyXSkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigic2FtcGxlX2lkIikgCgojIyBQcmVwIGZvciBwbG90dGluZwpkYXRhNHBsb3QgPC0gcGNhREYgJT4lIAogIGRwbHlyOjppbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSwgYnk9InNhbXBsZV9pZCIpICU+JSAKICBtdXRhdGUocmhhcHNvZHlfbGliID0gaWZlbHNlKHN0dWR5X2lkID09ICIyMDEzMDA0IiwiTGlicmFyeSAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzdHVkeV9pZCA9PSAiMjAxMzAwNyIsIkxpYnJhcnkgMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN0dWR5X2lkID09ICIyMDEzMDA4IiwiTGlicmFyeSAzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN0dWR5X2lkID09ICIyMDE4MDAyIiwiTGlicmFyeSA0IixOQSkpKSkpCgoKKHBsb3QucGNhLnJoYXBzb2R5IDwtIGRhdGE0cGxvdCAlPiUgCiAgICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IFRpbWUsZmlsbD1OVUxMLCBsYWJlbCA9IE5VTEwpKSArCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC45LCBzaXplID0gMSkgKwogICAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9IC4gJT4lIGZpbHRlcihzdHVkeV9pZCAlaW4lIHJoYXBzb2R5X3N0dWR5X2lkcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PVBDMSx5PVBDMiwgbGFiZWw9cmhhcHNvZHlfbGliKSxjb2xvcj0iZ3JleTEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsYm94LnBhZGRpbmcgPSAxLCBtYXgub3ZlcmxhcHMgPSBJbmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT0zLCBhbHBoYT0uOSxzaG93LmxlZ2VuZCA9IEYpICsKICAgIGdlb21fcG9pbnQoZGF0YT0gLiAlPiUgZmlsdGVyKHN0dWR5X2lkICVpbiUgcmhhcHNvZHlfc3R1ZHlfaWRzKSwKICAgICAgICAgICAgICAgYWVzKGNvbG9yPVRpbWUpLAogICAgICAgICAgICAgICBzaXplPTAuNSwgYWxwaGE9LjgpICsKICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTEsYWxwaGE9MSkpKSsKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IHRpbWUzX2NvbCkgKwogICAgbGFicyh4ID0gcGFzdGUwKCJQQzEgKCIsICB2YXJFeHBbMV0sICIgJSkiKSwKICAgICAgICAgeSA9IHBhc3RlMCgiUEMyICgiLCAgdmFyRXhwWzJdLCAiICUpIiksCiAgICAgICAgIHNoYXBlPSJSaGFwc29keSBsaWJyYXJ5IikgKwogICAgdGhlbWVfbWluaW1hbCgpICArCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAKICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSkpIApgYGAKCmxvYWQgc2V1cmF0IG9iamVjdCAmIHNldCBjb2xvcnMKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShTZXVyYXQpCiNwYm1jIDwtIHJlYWRSRFMoIi4uLy4uL01hbGFyaWFUcmF2ZWxsZXJfQWJTZXEvZGF0YS9TZXVyYXRPYmplY3RzLzIwMjEtMTItMTdBYlNlcV9DZWxsX0NhbGxpbmdfcWNfY2NhX3dubl9jbHVzdGVyaW5nX2Fubm90YXRlZC5yZHMiKQojcGJtYyA8LSByZWFkUkRTKCIuLi9kYXRhL2RhdGEvcmhhcHNvZHkvMjAyMS0xMi0xN0FiU2VxX0NlbGxfQ2FsbGluZ19xY19jY2Ffd25uX2NsdXN0ZXJpbmdfYW5ub3RhdGVkLnJkcyIpCnBibWMgPC0gcmVhZFJEUygiLi4vZGF0YS9kYXRhL3JoYXBzb2R5L01hbGFyaWFUcmF2ZWxlcl9SaGFwc29keUFiU2VxX0NlbGxfQ2FsbGluZ19xY19jY2Ffd25uX2NsdXN0ZXJpbmdfYW5ub3RhdGVkLnJkcyIpCgpwYm1jJEdyb3VwX3JldiA8LSBmYWN0b3IoYXMuZmFjdG9yKHBibWMkR3JvdXApLCBsZXZlbHMgPSBjKCJwcmltYXJ5IiwgInByZXZpb3VzbHkiKSkKCiMtIFJOQSBOb3JtYWxpemF0aW9uCnBibWMgPC0gTm9ybWFsaXplRGF0YShvYmplY3QgPSBwYm1jLCBhc3NheSA9ICdSTkEnLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICdMb2dOb3JtYWxpemUnLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCkKCiMtIEFiIE5vcm1hbGl6YXRpb24KcGJtYyA8LSBOb3JtYWxpemVEYXRhKG9iamVjdCA9IHBibWMsIGFzc2F5ID0gJ0FEVCcsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gJ0NMUicpICNtYXJnaW4JSWYgcGVyZm9ybWluZyBDTFIgbm9ybWFsaXphdGlvbiwgbm9ybWFsaXplIGFjcm9zcyBmZWF0dXJlcyAoMSkgb3IgY2VsbHMgKDIpCgojIyBsaXN0IG9mIHByb3RlaW5zL21ybmEgdGFyZ2V0cyBjb3ZlcmVkCmFiLm1hcmtlcnMgPC0gcm93bmFtZXMocGJtY0Bhc3NheXMkQURUKQpybmEubWFya2VycyA8LSByb3duYW1lcyhwYm1jQGFzc2F5cyRSTkEpCgojI2NoYW5nZSBncm91cCBjb2xvcgpFTkRFTUlDX2NvbG9ycyA8LSBzZXROYW1lcyhjKCIjRjFBMzQwIiwiIzk5OEVDMyIpLCBjKCJwcmV2aW91c2x5X2V4cG9zZWQiLCJwcmltYXJ5X2luZmVjdGVkIikpCiNwcmV2aW91c2x5X2V4cG9zZWQgICBwcmltYXJ5X2luZmVjdGVkIAojICAgICAgICAgIiNGMUEzNDAiICAgICAgICAgICIjOTk4RUMzIiAKRU5ERU1JQ19jb2xvcnMgPC0gc2V0TmFtZXMoYnJld2VyLnBhbCgzLCJQdU9yIilbYygxLDMpXSwgYygicHJldmlvdXNseV9leHBvc2VkIiwicHJpbWFyeV9pbmZlY3RlZCIpKQpuYW1lcyhFTkRFTUlDX2NvbG9ycykgPC0gYygicHJldmlvdXNseSIsInByaW1hcnkiKQpUSU1FX2NvbG9ycyA8LSBzZXROYW1lcyhicmV3ZXIucGFsKDYsIlBpWUciKSwgYygiQWN1dGUiLCJEMTAiLCJNMSIsIk0zIiwiTTYiLCJZMSIpKQoKc2NhbGVkXzAxX2NvbCA8LSBjaXJjbGl6ZTo6Y29sb3JSYW1wMihjKDAsMSksIGMoIndoaXRlIiwicmVkIikpCgpMMV9jb2xvcnMgPC0gbGVuZ3RoKHVuaXF1ZShwYm1jQG1ldGEuZGF0YSRDZWxsVHlwZV9MMSkpCkwxX2NvbG9ycyA8LSBjKCIjNjhhNzQ4IiwKICAgICAgICAgICAgICAgIiM4NzYxY2MiLAogICAgICAgICAgICAgICAiI2FlOTUzZSIsCiAgICAgICAgICAgICAgICIjNjg4YmNjIiwKICAgICAgICAgICAgICAgIiNjYzY5M2QiLAogICAgICAgICAgICAgICAiIzRhYWM4ZCIsCiAgICAgICAgICAgICAgICIjYzM2MWFhIiwKICAgICAgICAgICAgICAgIiNjYTUzNjkiKQpuYW1lcyhMMV9jb2xvcnMpIDwtIHVuaXF1ZShwYm1jQG1ldGEuZGF0YSRDZWxsVHlwZV9MMSkKCgpJZGVudHMocGJtYykgPC0gIkNlbGxUeXBlX0wyIgoKTDJfY29sb3JzIDwtIGxlbmd0aCh1bmlxdWUocGJtY0BtZXRhLmRhdGEkQ2VsbFR5cGVfTDIpKQpMMl9jb2xvcnMgPC0gYygibURDIj0iIzc5NjU4QyIsCiAgICAgICAgICAgICAgICJwREMiID0gIiNBRUExNEUiLAogICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIkNEMTQgbW9ub2N5dGVzIj0gIiNEMUVBQjciLAogICAgICAgICAgICAgICAiQ0QxNiBtb25vY3l0ZXMiPSIjREI3RDQ3IiwKICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICJWZDIrIGdkVCI9IiM3OTZDRDciLAogICAgICAgICAgICAgICAiVmQyLSBnZFQiID0gICIjNjZBQzU1IiwKICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICJOSyBDRDU2ZGltIENEMTYrIiA9ICIjRUJCNjlFIiwgCiAgICAgICAgICAgICAgICJOSyBDRDU2ZGltIiA9ICAiI0NFRTQ4NiIsCiAgICAgICAgICAgICAgICJOSyBDRDU2YnJpZ2h0Ij0gICIjRTBEQURCIiwKICAgICAgICAgICAgICAgIk5LIHByb2xpZi4iID0iI0I1RTdERiIsCiAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAiQiBuYWl2ZSIgPSAiIzg4OUFFNSIsCiAgICAgICAgICAgICAgICJCIG1lbW9yeSIgPSAiIzY2RUQ1OCIsCiAgICAgICAgICAgICAgICJQbGFzbWEgY2VsbHMiID0gIiM4OTNDRUEiLAogICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIkNENCBuYWl2ZSI9ICIjRTE1MDgxIiwKICAgICAgICAgICAgICAgIkNENCBUcmVnIENEODArIj0gIiM1NzkxODkiLAogICAgICAgICAgICAgICAiQ0Q0IFRyZWcgQ0Q4MC0iPSAgIiM2NkRFRTIiLAogICAgICAgICAgICAgICAiQ0Q0IFRmaCI9ICIjRDY0RURCIiwKICAgICAgICAgICAgICAgIkNENCBlZmZlY3QuIGFjdGl2YXRlZCIgPSAiI0QzOEQ5NiIsCiAgICAgICAgICAgICAgICJDRDQgZWZmZWN0LiBtZW1vcnkiID0gIiNFREQ1OTEiLAogICAgICAgICAgICAgICAiQ0Q0IHRyYW5zLiBtZW1vcnkiID0gICIjREFCOEUzIiwKICAgICAgICAgICAgICAgIkNENCBjZW50cmFsIG1lbW9yeSIgID0gIiM2RkU4QkUiLAogICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIkNEOCBuYWl2ZSI9ICIjQ0FFQjQ4IiwKICAgICAgICAgICAgICAgIkNEOCB0cmFucy4gbWVtb3J5Ij0gIiM4NUVCOEYiLAogICAgICAgICAgICAgICAiQ0Q4IFRmaCI9IiNFNkQyNTMiLAogICAgICAgICAgICAgICAiTktUIj0iIzdCQkNERiIsCiAgICAgICAgICAgICAgICJDRDggZWZmZWN0LiBtZW1vcnkiICA9ICAiI0E3QUU5MCIsIAogICAgICAgICAgICAgICAidW5kZWZpbmVkIj0gIiNEOTg0RDEiKQoKbmFtZXMoTDJfY29sb3JzKSA8LSB1bmlxdWUocGJtY0BtZXRhLmRhdGEkQ2VsbFR5cGVfTDIpCgpgYGAKCiMjIEZpZ3VyZSAzQSwgQwpgYGB7ciByaGFwc29keS11bWFwfQphcnIgPC0gbGlzdCh4ID0gLTEzLCB5ID0gLTEzLCB4X2xlbiA9IDUsIHlfbGVuID0gNSkKCnVtYXBfYXhpcyA8LSBhbm5vdGF0ZSgic2VnbWVudCIsIGxpbmV3aWR0aD0wLjEsCiAgICAgICAgICAgICAgICAgICAgICB4ID0gYXJyJHgsIHhlbmQgPSBhcnIkeCArIGMoYXJyJHhfbGVuLCAwKSwgCiAgICAgICAgICAgICAgICAgICAgICB5ID0gYXJyJHksIHllbmQgPSBhcnIkeSArIGMoMCwgYXJyJHlfbGVuKSwgCiAgICAgICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgbGVuZ3RoID0gdW5pdCgzLCAncHQnKSkpCnVtYXBfYXhpc194bGFiIDwtIGFubm90YXRlKCJ0ZXh0IiwgeCA9IGFyciR4KzIuNSwgeSA9IGFyciR4LTEsIGxhYmVsID0gIndublVNQVAgMSIsc2l6ZT0xKSAKdW1hcF9heGlzX3lsYWIgPC0gYW5ub3RhdGUoInRleHQiLCB5ID0gYXJyJHkrMi41LCB4ID0gYXJyJHktMSwgbGFiZWwgPSAid25uVU1BUCAyIixzaXplPTEsYW5nbGU9OTApCgoKcmhhcHNvZHlfdW1hcF9jb29yZHMgPC0gZGF0YS50YWJsZTo6ZGF0YS50YWJsZShwYm1jQG1ldGEuZGF0YSwgRW1iZWRkaW5ncyhvYmplY3QgPSBwYm1jLCByZWR1Y3Rpb24gPSAnd25uLnVtYXAnKSkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigiQ2VsbElEIikgCgpsYWJsZV9kZiA8LSByaGFwc29keV91bWFwX2Nvb3JkcyAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoQ2VsbFR5cGVfTDEpICU+JQogIGRwbHlyOjpzZWxlY3QoQ2VsbFR5cGVfTDEsIGNvbnRhaW5zKCJVTUFQIikpICU+JQogIHN1bW1hcmlzZV9hbGwobWVhbikKCihyaGFwc29keV91bWFwX2dncGxvdF9sMSA8LSByaGFwc29keV91bWFwX2Nvb3JkcyAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSB3bm5VTUFQXzEsIHkgPSB3bm5VTUFQXzIpKSArIAogICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBhcy5jaGFyYWN0ZXIoQ2VsbFR5cGVfTDEpKSwgc2l6ZSA9IDAuMSwgYWxwaGE9LjUsIHNob3cubGVnZW5kID0gRixzaGFwZSA9IDE2KSArCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YT1sYWJsZV9kZixhZXMoeD13bm5VTUFQXzEseT13bm5VTUFQXzIsIGxhYmVsPUNlbGxUeXBlX0wxKSxzaXplPTEuNSkgKwogICAgICAgIGNvb3JkX2ZpeGVkKCkrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPUwxX2NvbG9ycykgKwogICAgdGhlbWVfdm9pZCgpICsKICAgICAgICAgICAgICAgIHVtYXBfYXhpcyArCiAgICAgICAgICAgICAgICB1bWFwX2F4aXNfeGxhYiArCiAgICAgICAgICAgICAgICB1bWFwX2F4aXNfeWxhYikKCmxhYmxlX2RmIDwtIHJoYXBzb2R5X3VtYXBfY29vcmRzICU+JQogIGRwbHlyOjpncm91cF9ieShDZWxsVHlwZV9MMikgJT4lCiAgZHBseXI6OnNlbGVjdChDZWxsVHlwZV9MMiwgY29udGFpbnMoIlVNQVAiKSkgJT4lCiAgc3VtbWFyaXNlX2FsbChtZWFuKQoKKHJoYXBzb2R5X3VtYXBfZ2dwbG90X2wyIDwtIHJoYXBzb2R5X3VtYXBfY29vcmRzICU+JSAKICAgIGdncGxvdChhZXMoeCA9IHdublVNQVBfMSwgeSA9IHdublVNQVBfMikpICsgCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGFzLmNoYXJhY3RlcihDZWxsVHlwZV9MMikpLCBzaXplID0gMC4xLCBhbHBoYT0uNSwgc2hvdy5sZWdlbmQgPSBGLCBzaGFwZSA9IDE2KSArIAogICAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9bGFibGVfZGYsYWVzKHg9d25uVU1BUF8xLHk9d25uVU1BUF8yLCBsYWJlbD1DZWxsVHlwZV9MMiksc2l6ZT0xLjUpICsKICAgIGxhYnMoeCA9ICd3bm5VTUFQIDEnLCB5ID0gJ3dublVNQVAgMicsIGNvbG9yPU5VTEwpICArIAogICAgY29vcmRfZml4ZWQoKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9TDJfY29sb3JzKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgICAgICAgICAgICAgdW1hcF9heGlzICsKICAgICAgICAgICAgICAgIHVtYXBfYXhpc194bGFiICsKICAgICAgICAgICAgICAgIHVtYXBfYXhpc195bGFiKQpgYGAKCiMjIEZpZ3VyZSAzQgpgYGB7cn0KcmVxdWlyZShzY2FsZXMpCihwZXJfc2FtcGxlX3BlcmNfbDEgPC0gdGliYmxlKHBibWNAbWV0YS5kYXRhKSAlPiUgCiAgICBtdXRhdGUob3JpZy5pZGVudCA9IHBhc3RlMCgiUGF0aWVudCIsIiAwIixMaWJyYXJ5KSkgJT4lIAogICAgZ3JvdXBfYnkoVGltZSxvcmlnLmlkZW50KSAlPiUgCiAgICBjb3VudChDZWxsVHlwZV9MMSkgJT4lIAogICAgIyBTdGFja2VkICsgcGVyY2VudAogICAgZ2dwbG90KGFlcyhmaWxsID0gQ2VsbFR5cGVfTDEsIHk9biwgeD1vcmlnLmlkZW50KSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIiwgc3RhdD0iaWRlbnRpdHkiLHdpZHRoID0gMC45KSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBMMV9jb2xvcnMpICsKICAgIGZhY2V0X2dyaWQoflRpbWUsc2NhbGVzID0gImZyZWVfeCIpICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQsZXhwYW5kID0gYygwLDApKSArIAogICAgbGFicyh4ID0gIiIsCiAgICAgICAgIHkgPSAiRnJlcXVlbmN5IiwKICAgICAgICAgZmlsbD0iIikgKwogICAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSA2KSArCiAgICAjdGhlbWVfY293cGxvdCgpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCkpKQpgYGAKCiMjIEZpZ3VyZSAzRAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGJtY19hY3V0ZSA8LSBzdWJzZXQocGJtYywgc3Vic2V0PVRpbWU9PSJBY3V0ZSIpCgojLSBSTkEgTm9ybWFsaXphdGlvbgpwYm1jX2FjdXRlIDwtIE5vcm1hbGl6ZURhdGEob2JqZWN0ID0gcGJtY19hY3V0ZSwgYXNzYXkgPSAnUk5BJywgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAnTG9nTm9ybWFsaXplJywgc2NhbGUuZmFjdG9yID0gMTAwMDApICU+JSBTY2FsZURhdGEoKQoKIy0gQWIgTm9ybWFsaXphdGlvbgpwYm1jX2FjdXRlIDwtIE5vcm1hbGl6ZURhdGEob2JqZWN0ID0gcGJtY19hY3V0ZSwgYXNzYXkgPSAnQURUJywgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAnQ0xSJykgI21hcmdpbglJZiBwZXJmb3JtaW5nIENMUiBub3JtYWxpemF0aW9uLCBub3JtYWxpemUgYWNyb3NzIGZlYXR1cmVzICgxKSBvciBjZWxscyAoMikKCmBgYAoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIFBzZXVkb2J1bGsgKENlbGx0eXBlKQoKI2h0dHBzOi8vZ2l0aHViLmNvbS9zYXRpamFsYWIvc2V1cmF0L2Rpc2N1c3Npb25zLzQyMTAKIyMgQXZlcmFnZUV4cHJlc3Npb24KSWRlbnRzKHBibWNfYWN1dGUpIDwtICJDZWxsVHlwZV9MMiIKCiMjIGNhbGN1bGF0aW9uIG9mIHBzZXVkb2J1bGssIGZvciBlYWNoIGlkZW50aXR5IGJhc2VkIG9uIGNvdW50IGRhdGEKcGJtY19hY3V0ZS5hdmcud2lkZSA8LSBsb2cxcChTZXVyYXQ6OkF2ZXJhZ2VFeHByZXNzaW9uKHBibWNfYWN1dGUsIGdyb3VwLmJ5ID0gIkNlbGxUeXBlX0wyIiwgc2xvdCA9ICJjb3VudHMiLCB2ZXJib3NlID0gRkFMU0UpJFJOQSkgJT4lIAogIGRhdGEuZnJhbWUoKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJnZW5lIikgCgpjb2xuYW1lcyhwYm1jX2FjdXRlLmF2Zy53aWRlKSA8LSBjKCJnZW5lIixjb2xuYW1lcyhTZXVyYXQ6OkF2ZXJhZ2VFeHByZXNzaW9uKHBibWNfYWN1dGUsIGdyb3VwLmJ5ID0gIkNlbGxUeXBlX0wyIiwgc2xvdCA9ICJjb3VudHMiLCB2ZXJib3NlID0gRkFMU0UpJFJOQSkpCgpwYm1jX2FjdXRlLmF2Zy5sb25nIDwtIHBibWNfYWN1dGUuYXZnLndpZGUgJT4lIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJjZWxsdHlwZSIsIHZhbHVlc190byA9ICJhdmdFeHAiLGNvbHMgPSAtZ2VuZSkKYGBgCgoKTWFwcGluZyAoZ2VuZSAtIHByb3RlaW4pCgpgYGB7cn0KIyMgbWFwcGluZyAKZnVsbF9tYXBwaW5nIDwtIG1hcHBpbmdfdW5pcHJvdF9lbnNlbWJsICU+JSBsZWZ0X2pvaW4oaHBhXzI0LjAsIGJ5PWMoIkVuc2VtYmwiPSJlbnNlbWJsIikpCgp3aWxjb3hVcCA8LSBkYXAucmVzICU+JSBmaWx0ZXIoRkRSPT1UUlVFLGxvZ0ZDPjEpICU+JSBwdWxsKFVuaVByb3QpCgpnZW5lLnNlbGVjdGlvbiA8LSBmdWxsX21hcHBpbmcgJT4lIAogIGZpbHRlcihVbmlQcm90ICVpbiUgd2lsY294VXApICU+JSAKICBmaWx0ZXIoU3ltYm9sICVpbiUgcm5hLm1hcmtlcnMpICU+JSBkaXN0aW5jdChBc3NheSkgJT4lIHB1bGwoQXNzYXkpCmBgYAoKIyMgRmlndXJlIDNECkhlYXRtYXAgZ2VuZXMgZXhwcmVzc2lvbgoKYGBge3IgaG0tYWN1dGUtZ2V4LXdpZGV9CnJoYXBzb2R5LmdlbmUubWF0Y2ggPC0gZnVsbF9tYXBwaW5nICU+JSAKICBmaWx0ZXIoVW5pUHJvdCAlaW4lIHdpbGNveFVwKSAlPiUgCiAgZmlsdGVyKFN5bWJvbCAlaW4lIHVuaXF1ZShwYm1jX2FjdXRlLmF2Zy53aWRlJGdlbmUpKQoKIyMgbWFrZSBtYXRyaXggZm9yIGhlYXRtYXAKbWF0X3BibWNfYWN1dGUgPC0gcGJtY19hY3V0ZS5hdmcud2lkZSAlPiUgCiAgZmlsdGVyKGdlbmUgJWluJSByaGFwc29keS5nZW5lLm1hdGNoJFN5bWJvbCkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygiZ2VuZSIpICU+JSAKICBhcy5tYXRyaXgoKSAKCiMjIG1ha2Ugcm93KGdlbmUvcHJvdGVpbikgYW5ub3RhdGlvbiBkZgpyb3dBbm5vLmRmIDwtIGRhdGEuZnJhbWUoQXNzYXkgPSByb3duYW1lcyhtYXRfcGJtY19hY3V0ZSkpICU+JSAKICBsZWZ0X2pvaW4oZGFwLnJlcyxieT1jKCJBc3NheSIpKSAlPiUgCiAgI2xlZnRfam9pbihocGFfMjQuMCxieT1jKCJBc3NheSI9ImdlbmUiKSkgJT4lIAogICAgbGVmdF9qb2luKGhwYV8yNC4wLGJ5PWMoIlVuaVByb3QiPSJ1bmlwcm90IikpICU+JSAKCiAgbXV0YXRlKHNlY3JldG9tZV9mdW5jdGlvbiA9IGlmZWxzZShpcy5uYShzZWNyZXRvbWVfZnVuY3Rpb24pLCJObyBhbm5vdGF0ZWQgZnVuY3Rpb24iLCBzZWNyZXRvbWVfZnVuY3Rpb24pKQogIAoKY29sLmFubm8uZGYgPC0gZGF0YS5mcmFtZShjb2xuYW1lcyA9IGNvbG5hbWVzKG1hdF9wYm1jX2FjdXRlKSkgJT4lIAogIHRyYW5zbXV0ZShjb2xuYW1lcywKICAgICAgICAgICAgY29sYW5ubyA9IGNhc2Vfd2hlbihncmVwbCgiREMiLGNvbG5hbWVzKSB+ICJEQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm1vbm9jeXRlcyIsY29sbmFtZXMpIH4gIk1vbm9jeXRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkNENCIsY29sbmFtZXMpIH4gIkNENCsgVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkNEOCIsY29sbmFtZXMpIH4gIkNEOCsgVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkJ8UGxhc21hIixjb2xuYW1lcykgfiAiQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIk5LIixjb2xuYW1lcykgfiAiTksiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJnZFQiLGNvbG5hbWVzKSB+ICJnZFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gInVuZGVmaW5lZCIpLAogICAgICAgICAgICBjb2xhbm5vID0gZmFjdG9yKGNvbGFubm8sIGxldmVscz0gYygiREMiLCJNb25vY3l0ZXMiLCJOSyIsImdkVCIsIkIiLCJDRDQrIFQiLCJDRDgrIFQiLCJ1bmRlZmluZWQiKSkpCgoKcmlnaHQuYW5ubyA8LSBIZWF0bWFwQW5ub3RhdGlvbihkZiA9IGNvbC5hbm5vLmRmICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoImNvbG5hbWVzIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gInJvdyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChjb2xhbm5vID0gTDFfY29sb3JzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG5hbWUgPSAiU05GIGNsdXN0ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfYW5ub3RhdGlvbl9uYW1lID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2xlZ2VuZCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9uYW1lX2dwID0gZ3Bhcihmb250c2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhvcml6b250YWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCguMSwgImNtIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KC4yLCAiY20iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcGxlX2Fubm9fc2l6ZSA9IHVuaXQoMSwgIm1tIikpCgp0b3AuYW5ubyA8LSAgSGVhdG1hcEFubm90YXRpb24oZGYgPSByb3dBbm5vLmRmICU+JSB0cmFuc211dGUoQXNzYXksIHNlY3JldG9tZV9sb2NhdGlvbikgJT4lIGNvbHVtbl90b19yb3duYW1lcygiQXNzYXkiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gImNvbHVtbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2xlZ2VuZCA9IGMoVFJVRSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19hbm5vdGF0aW9uX25hbWUgPSBGLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kX3BhcmFtID0gbGlzdCh0aXRsZSA9ICJIUEFcbmNsYXNzaWZpY2F0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDMsICJtbSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCgzLCAibW0iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBsaXN0KHNlY3JldG9tZV9sb2NhdGlvbiA9IGMoc2VjcmV0b21lX2xvY2F0aW9uX2NvbHMpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDMsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYV9jb2wgPSAiZ3JleTkwIikKCiMjIGdldHRpbmcgZm9sZGNoYW5nZSAoZE5QWCBvdmVyIG1lZGlhbiBjb252YWxlc2NlbmNlKSAKbSA8LSBmY19vdmVyX21lZGlhbl9NMTIgJT4lCiAgZmlsdGVyKEFzc2F5ICVpbiUgcm93QW5uby5kZiRBc3NheSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBBc3NheSwgdmFsdWVzX2Zyb20gPSBkTlBYLGlkX2NvbHMgPSBzdHVkeV9pZCkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic3R1ZHlfaWQiKSAlPiUgCiAgYXMubWF0cml4KCkgJT4lIHQoKQoKbSA8LSBtW3Jvd25hbWVzKG1hdF9wYm1jX2FjdXRlKSxdCgoKYm90dG9tLmFubm8gPC0gSGVhdG1hcEFubm90YXRpb24oIlBsYXNtYSBwcm90ZWluXG5kTlBYIiA9IGFubm9fYm94cGxvdCh0KG0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IHVuaXQoMS41LCAiY20iKSx3aWR0aCA9IHVuaXQoMS41LCJjbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJveF93aWR0aCA9IDAuOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzX3BhcmFtID0gbGlzdChzaWRlID0gInJpZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfcm90ID0gNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3A9Z3Bhcihmb250c2l6ZSA9IDUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncCA9IGdwYXIoZmlsbD0iI0M1MUI3RCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGxpbmUgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9yb3QgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9zaWRlID0gInJpZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcGxlX2Fubm9fc2l6ZSA9IHVuaXQoMywgIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gImNvbHVtbiIpCgoKCihwYm1jX2wyX2FjdXRlX2htLndpZGUgPC0gbWF0X3BibWNfYWN1dGVbcm93bmFtZXMobSksXSAlPiUgCiAgICB0KCkgJT4lIAogICAgIyMgc2NhbGUgdmFsdWVzIGZyb20gMC0xCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gc2NhbGVzOjpyZXNjYWxlKC4sIHRvPWMoMCwxKSkpKSAlPiUgCiAgICBhcy5tYXRyaXgoKSAlPiUgCiAgICBDb21wbGV4SGVhdG1hcDo6SGVhdG1hcCgKICAgICAgbmFtZT0iYXZlcmFnZVxuZ2VuZVxuZXhwcmVzc2lvbiIsCiAgICAgIGNvbCA9IHNjYWxlZF8wMV9jb2wsCiAgICAgIAogICAgICB0b3BfYW5ub3RhdGlvbiA9IHRvcC5hbm5vLAogICAgICBib3R0b21fYW5ub3RhdGlvbiA9IGJvdHRvbS5hbm5vLAogICAgICByaWdodF9hbm5vdGF0aW9uID0gIHJpZ2h0LmFubm8sCiAgICAgIGNvbHVtbl9kZW5kX2hlaWdodCA9IHVuaXQoMiwgIm1tIiksCiAgICAgIGNsdXN0ZXJfcm93cyA9IEYsCiAgICAgIHJvd19kZW5kX3Jlb3JkZXIgPSBUUlVFLAogICAgICBzaG93X3Jvd19uYW1lcyA9IFRSVUUsCiAgICAgIGNvbHVtbl9zcGxpdCA9IHJvd0Fubm8uZGYkc2VjcmV0b21lX2Z1bmN0aW9uLAogICAgICBjb2x1bW5fZGVuZF9yZW9yZGVyID0gRiwKICAgICAgcm93X3RpdGxlX3NpZGUgPSAicmlnaHQiLAogICAgICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IFQsCiAgICAgIHJvd19zcGxpdCA9IGNvbC5hbm5vLmRmJGNvbGFubm8sCiAgICAgIHJvd190aXRsZSA9IE5VTEwsCiAgICAgIAogICAgICBjb2x1bW5fdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplPTQpLAogICAgICBjb2x1bW5fdGl0bGVfcm90ID0gNDUsCiAgICAgIHJvd190aXRsZV9yb3QgPSAwLAogICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNCksCiAgICAgICNyb3dfZGVuZF93aWR0aCA9IHVuaXQoMiwgIm1tIiksIAogICAgICByb3dfZGVuZF9zaWRlID0gImxlZnQiLAogICAgICBjbHVzdGVyX3Jvd19zbGljZXMgPSBULAogICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNCksIAogICAgICBjb2x1bW5fbmFtZXNfcm90ID0gOTAsCiAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KDMsICJtbSIpKSwKICAgICkgCiAgKQpgYGAKCgoKIyMgRmlndXJlIDNFCkNlbGxQaG9uZURCCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojY3BkYi5wcm90ZWluX2lucHV0IDwtIHJlYWRfZGVsaW0oIi4uL2RhdGEvY2VsbHBob25lREIvdjQuMS4wX3Byb3RlaW5faW5wdXQuY3N2IikKI2NwZGIuaW50ZXJhY3Rpb25faW5wdXQgPC0gcmVhZF9kZWxpbSgiLi4vZGF0YS9jZWxscGhvbmVEQi92NC4xLjBfaW50ZXJhY3Rpb25faW5wdXQuY3N2IikKCmNwZGIucHJvdGVpbl9pbnB1dCA8LSByZWFkX2RlbGltKCIuLi9kYXRhL2NlbGxwaG9uZURCL3Y1X3Byb3RlaW5faW5wdXQuY3N2IiwpCmNwZGIuaW50ZXJhY3Rpb25faW5wdXQgPC0gcmVhZF9kZWxpbSgiLi4vZGF0YS9jZWxscGhvbmVEQi92NV9pbnRlcmFjdGlvbl9pbnB1dC5jc3YiKQoKa2VnZy5jY3IgPC0gcmVhZF9leGNlbCgiLi4vZGF0YS9LRUdHX0N5dG9raW5lQ3l0b2tpbmVSZWNlcHRvckludGVyYWN0aW9uX21hbGFyaWFzcGVjLnhsc3giKSAlPiUgbXV0YXRlKFNvdXJjZSA9ICJLRUdHIikKYGBgCgpgYGB7cn0Kcm5hLm1hcmtlcnMudW5pcHJvdCA8LSBkYXRhLmZyYW1lKGdlbmUgPSBybmEubWFya2VycykgJT4lIAogIGxlZnRfam9pbihocGFfMjQuMCAlPiUgdHJhbnNtdXRlKGdlbmUsIHVuaXByb3QpKSAlPiUgbmEub21pdCgpCmBgYAoKYGBge3J9CmxpZ2FuZC5xIDwtIGRhcC5yZXMgJT4lIGZpbHRlcihwLmFkaiA8PTAuMDEsIGxvZ0ZDID4gLjEpICU+JSAKICBsZWZ0X2pvaW4oY3BkYi5wcm90ZWluX2lucHV0LAogICAgICAgICAgICBieT1jKCJVbmlQcm90Ij0idW5pcHJvdCIpKSAlPiUgCiAgcHVsbChVbmlQcm90KQoKbGVuZ3RoKGxpZ2FuZC5xKQoKbncgPC0gY3BkYi5pbnRlcmFjdGlvbl9pbnB1dCAlPiUgCiAgZmlsdGVyKHBhcnRuZXJfYSAlaW4lIGxpZ2FuZC5xLAogICAgICAgICBkaXJlY3Rpb25hbGl0eSA9PSAiTGlnYW5kLVJlY2VwdG9yIikgJT4lIAogIG11dGF0ZShwcm90ZWluX25hbWVfYl9zdHJpcCA9IGdzdWIoIl9IVU1BTiIsIiIscHJvdGVpbl9uYW1lX2IpLAogICAgICAgICBwcm90ZWluX25hbWVfYSA9IGdzdWIoIl9IVU1BTiIsIiIscHJvdGVpbl9uYW1lX2EpKSAlPiUgCiAgbXV0YXRlKHByb3RlaW5fbmFtZV9iX2NvbXBsZXggPSBjYXNlX3doZW4oaXMubmEocHJvdGVpbl9uYW1lX2IpIH4gc3RyX3JlbW92ZShpbnRlcmFjdG9ycyxwYXN0ZTAocHJvdGVpbl9uYW1lX2EsIi0iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gcHJvdGVpbl9uYW1lX2IpKSAlPiUKICAgc2VwYXJhdGVfbG9uZ2VyX2RlbGltKHByb3RlaW5fbmFtZV9iX2NvbXBsZXgsIGRlbGltID0gIisiKSAlPiUgCiAgIGxlZnRfam9pbihocGFfMjQuMCAlPiUgdHJhbnNtdXRlKHByb3RlaW5fbmFtZV9iX2NvbXBsZXggPSBnZW5lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXByb3RfYl9jb21wbGV4ID0gdW5pcHJvdCksIGJ5PWMoInByb3RlaW5fbmFtZV9iX2NvbXBsZXgiKSkgJT4lIAogIG11dGF0ZShwcm90ZWluX25hbWVfYiA9IGNhc2Vfd2hlbihpcy5uYShwcm90ZWluX25hbWVfYikgfiBwcm90ZWluX25hbWVfYl9jb21wbGV4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBwcm90ZWluX25hbWVfYiksCiAgICAgICAgIHBhcnRuZXJfYl9uZXcgPSBjYXNlX3doZW4oaXMubmEodW5pcHJvdF9iX2NvbXBsZXgpIH4gcGFydG5lcl9iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gdW5pcHJvdF9iX2NvbXBsZXgpKSAlPiUgCiAgdHJhbnNtdXRlKHBhcnRuZXJfYSwgcGFydG5lcl9iLCBwYXJ0bmVyX2JfbmV3KSAlPiUgCiAgZmlsdGVyKHBhcnRuZXJfYl9uZXcgJWluJSBybmEubWFya2Vycy51bmlwcm90JHVuaXByb3QpICU+JSAKICBtdXRhdGUodW5pcHJvdF9hID0gcGFydG5lcl9hLAogICAgICAgICB1bmlwcm90X2IgPSBwYXJ0bmVyX2JfbmV3KQpgYGAKCmBgYHtyfQptZWFzdXJlZC5pbi5wbGFzbWEgPC0gZGFwLnJlcyAlPiUgZmlsdGVyKHAuYWRqIDw9MC4wMSwgbG9nRkMgPiAwLjEpICU+JSBwdWxsKFVuaVByb3QpCm1lYXN1cmVkLmluLnBsYXNtYS5uYW1lIDwtIGRhcC5yZXMgJT4lIGZpbHRlcihwLmFkaiA8PTAuMDEsIGxvZ0ZDID4gLjEpICU+JSBwdWxsKEFzc2F5KQoKRyA8LSBhc190YmxfZ3JhcGgobncgJT4lIHRyYW5zbXV0ZShmcm9tID0gdW5pcHJvdF9hLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gdW5pcHJvdF9iKSkKbm9kZV90YWJsZSA8LSBhc190aWJibGUoRykgJT4lIAogIGxlZnRfam9pbihkYXAucmVzICU+JSBtdXRhdGUobWVhc3VyZWQuYXMuc29sdWJsZSA9IFQpLAogICAgICAgICAgICBieT1jKCJuYW1lIj0iVW5pUHJvdCIpKSAlPiUgCiAgbGVmdF9qb2luKGhwYV8yNC4wICU+JSB0cmFuc211dGUoZ2VuZSwgdW5pcHJvdCksIAogICAgICAgICAgICBieT1jKCJuYW1lIj0idW5pcHJvdCIpKSAlPiUgCiAgbXV0YXRlKHByb3RlaW5fbmFtZSA9IGdlbmUsCiAgICAgICAgIG1lYXN1cmVkLmFzLnNvbHVibGUgPSBjYXNlX3doZW4oaXMubmEobWVhc3VyZWQuYXMuc29sdWJsZSkgfkYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBUKSkjICU+JQpgYGAKCmBgYHtyfQoobGlnYW5kX3JlY2VwdG9yX253IDwtIEcgJT4lIAogICBpbm5lcl9qb2luKG5vZGVfdGFibGUsYnk9Im5hbWUiKSAlPiUgCiAgIGNyZWF0ZV9sYXlvdXQobGF5b3V0ID0gImZyIikgJT4lIAogICBnZ3JhcGgoKSArIAogICBnZW9tX2VkZ2VfbGluayhhbHBoYT0uMDIpICsgCiAgIGdlb21fZWRnZV9mYW4od2lkdGggPSAuNSwgY29sb3IgPSAiZ3JleTkwIikgKwogICBnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG9yPWlmX2Vsc2UobWVhc3VyZWQuYXMuc29sdWJsZT09VCxsb2dGQyxOQSksCiAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT0gaWZfZWxzZShtZWFzdXJlZC5hcy5zb2x1YmxlPT1ULGxvZ0ZDLDEpKSkgKwogICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAzLCBiYXJoZWlnaHQgPSAuNzUpLAogICAgICAgICAgc2l6ZT1GKSArCiAgIGxhYnMoY29sb3I9ImxvZ0ZDIG9mIHByb3RlaW5zXG5pbiBwbGFzbWEiKSArCiAgIHNjYWxlX3NpemUocmFuZ2U9YygxLDMuNSkpICsKICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gcHJvdGVpbl9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgY29sb3I9IGlmX2Vsc2UobWVhc3VyZWQuYXMuc29sdWJsZT09VCxsb2dGQyxOQSkpLAogICAgICAgICAgICAgICAgICBzaXplPTEsIAogICAgICAgICAgICAgICAgICByZXBlbD1UKSArCiAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93PSJ0aGlzdGxlMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGlnaD0iZGFya3JlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlPSJjb2xvcmJhciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWU9ImdyZXkyMCIpICsKICAgdGhlbWVfdm9pZCgpICsKICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KCBzaXplPTYpLAogICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSkgCikKYGBgCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcmVjZXB0b3JfZmFtIDwtIGxpc3QoY3hjX3N1YmZhbSA9IGMoIkNYQ1IxIiwiQ1hDUjIiLCJDWENSMyIsIkNYQ1I0IiwiQ1hDUjUiLCJDWENSNiIsIkNYQ1I3IiwiWENSMSIsIkNYM0NSMSIpLAogICAgICAgICAgICAgICAgICAgICBjY19zdWJmYW0gPSBwYXN0ZTAoIkNDUiIsMToxMSksCiAgICAgICAgICAgICAgICAgICAgIGNsYXNzMWhlbGljYWxjeXRvX2ZhbSA9IGMoIklMMlJBIiwiSUw0UiIpLAogICAgICAgICAgICAgICAgICAgICBjbGFzczJoZWxpY2FsY3l0b19mYW0gPSBjKCJJTDEwUkEiLCJJTDEwUkIiKSwKICAgICAgICAgICAgICAgICAgICAgcHJvbGFjdGlvbl9mYW0gPSBjKCJHSFIiLCJDU0YzUiIpLAogICAgICAgICAgICAgICAgICAgICBpZm5fZmFtID1jKCJJRk5BUjEiLCJJRk5BUjIiLCJJRk5HUjEiLCJJRk5HUjIiKSwKICAgICAgICAgICAgICAgICAgICAgaWwxbGlrZWN5dG9fZmFtID0gYygiSUwxUjEiLCJJTDFSQVAiLCJJTDFSMiIsIklMMThSMSIsIklMMThSQVAiLCJTVDIiLCJJTDFSQVAiKSwKICAgICAgICAgICAgICAgICAgICAgbm9uY2xhc3NpZmllZCA9IGMoIkNENCIsIkNTRjFSIiksCiAgICAgICAgICAgICAgICAgICAgIHRuZl9mYW0gPSBjKCJUTkZSMSIsIlRORlIyIiwiSFZFTSIsIkZBUyIsIkRSNCIsIkRSNSIsIkRDUjEiLCJEQ1IyIiwiRURBUiIsIlJBTksiLCJDRDI3IiwiQ0QzMCIsIkNENDAiLCJPeDQwIiwiVEFDSSIpLAogICAgICAgICAgICAgICAgICAgICB0Z2ZiX2ZhbSA9IGMoIlRHRkJSMiIsIkFDVlIyQiIsIkFDVlIxQiIpKSAlPiUgCiAgZW5mcmFtZSgpICU+JSB1bm5lc3QoY29scyA9IGModmFsdWUpKSAlPiUgZHBseXI6OnJlbmFtZShzdWJmYW0gPSBuYW1lLCByZWNlcHRvciA9IHZhbHVlKQpgYGAKCgpgYGB7cn0KI2V4dHJhY3QgYWxsIHRyYW5zbWVtYnJhbmUgcmVjZXB0b3JzIGZyb20gQ2VsbFBob25lREIgYXMgdW5pcHJvdElEcwoKIyMgZmlsdGVyIENlbGxQaG9uZURCIHByb3RlaW5faW5wdXQgZm9yIHRyYW5zbWVtYnJhbmUgJiByZWNlcHRvcnMKY3BkYi5yZWNlcHRvci50cmFuc21lbS5uYW1lIDwtIGNwZGIucHJvdGVpbl9pbnB1dCAlPiUgZmlsdGVyKHRyYW5zbWVtYnJhbmU9PVQgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNlcHRvcj09VCkgJT4lIAogIG11dGF0ZShwcm90ZWluX25hbWUgPSBnc3ViKCJfSFVNQU4iLCIiLHByb3RlaW5fbmFtZSkpICU+JSAKICBwdWxsKHVuaXByb3QpCmBgYAoKCmBgYHtyfQpkZiA8LSBwYm1jX2FjdXRlLmF2Zy53aWRlICU+JSAKICByaWdodF9qb2luKHJuYS5tYXJrZXJzLnVuaXByb3QpICU+JSAKICBmaWx0ZXIodW5pcHJvdCAlaW4lIG53JHVuaXByb3RfYikKCmdlbmVBbm5vIDwtIGRmICU+JSB0cmFuc211dGUoZ2VuZSx1bmlwcm90KSAlPiUgbGVmdF9qb2luKHJlY2VwdG9yX2ZhbSxieT1jKCJnZW5lIj0icmVjZXB0b3IiKSkgJT4lCiAgbXV0YXRlKHN1YmZhbSA9IGlmZWxzZShpcy5uYShzdWJmYW0pLCJPdGhlciIsc3ViZmFtKSwKICAgICAgICAgQ1BEQiA9IGlmZWxzZSh1bmlwcm90ICVpbiUgY3BkYi5yZWNlcHRvci50cmFuc21lbS5uYW1lLFQsRiksCiAgICAgICAgIEtFR0cgPSBpZmVsc2UoZ2VuZSAlaW4lIHJlY2VwdG9yX2ZhbSRyZWNlcHRvcixULEYpLAogICAgICAgICBpbl9wbGFzbWEgPSBpZmVsc2UoZ2VuZSAlaW4lIG1lYXN1cmVkLmluLnBsYXNtYS5uYW1lLFQsRikpCgoKbWF0IDwtIGRmICU+JSAKICBkcGx5cjo6c2VsZWN0KC11bmlwcm90KSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJnZW5lIikgJT4lIAogIGFzLm1hdHJpeCgpCgpjb2wuYW5uby5kZiA8LSBkYXRhLmZyYW1lKGNvbG5hbWVzID0gY29sbmFtZXMobWF0KSkgJT4lIAogIHRyYW5zbXV0ZShjb2xuYW1lcywKICAgICAgICAgICAgY29sYW5ubyA9IGNhc2Vfd2hlbihncmVwbCgiREMiLGNvbG5hbWVzKSB+ICJEQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm1vbm9jeXRlcyIsY29sbmFtZXMpIH4gIk1vbm9jeXRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkNENCIsY29sbmFtZXMpIH4gIkNENCsgVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkNEOCIsY29sbmFtZXMpIH4gIkNEOCsgVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkJ8UGxhc21hIixjb2xuYW1lcykgfiAiQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIk5LIixjb2xuYW1lcykgfiAiTksiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJnZFQiLGNvbG5hbWVzKSB+ICJnZFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gInVuZGVmaW5lZCIpLAogICAgICAgICAgICBjb2xhbm5vID0gZmFjdG9yKGNvbGFubm8sIGxldmVscz0gYygiREMiLCJNb25vY3l0ZXMiLCJOSyIsImdkVCIsIkIiLCJDRDQrIFQiLCJDRDgrIFQiLCJ1bmRlZmluZWQiKSkpCgpjb2xBbm4udG9wIDwtIEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gY29sLmFubm8uZGYgJT4lIGNvbHVtbl90b19yb3duYW1lcygiY29sbmFtZXMiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2ggPSAiY29sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBsaXN0KGNvbGFubm8gPSBMMV9jb2xvcnMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfYW5ub3RhdGlvbl9uYW1lID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2xlZ2VuZCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9uYW1lX2dwID0gZ3Bhcihmb250c2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhvcml6b250YWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCguMSwgImNtIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KC4yLCAiY20iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcGxlX2Fubm9fc2l6ZSA9IHVuaXQoMSwgIm1tIikKKQpgYGAKCiMjIEZpZ3VyZSAzRgpgYGB7ciBobS1hY3V0ZS1yZWNlcHRvci1nZXgtd2lkZX0KbSA8LSAgbWF0ICU+JSAKICB0KCkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiBzY2FsZXM6OnJlc2NhbGUoLiwgdG89YygwLDEpKSkpICU+JSAKICBhcy5tYXRyaXgoKSAKCihwYm1jX2wyX2FjdXRlX2NlbGxwaG9uZWRiX2htLndpZGUgPC0gbSAlPiUgCiAgIENvbXBsZXhIZWF0bWFwOjpIZWF0bWFwKG5hbWU9ImF2ZXJhZ2VcbmdlbmVcbmV4cHJlc3Npb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fc3BsaXQgPSBnZW5lQW5ubyRzdWJmYW0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbl9zbGljZXMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICBib3R0b21fYW5ub3RhdGlvbiA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmPWdlbmVBbm5vICU+JSB0cmFuc211dGUoaW5fcGxhc21hKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaD0iY29sdW1uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QodGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaW1wbGVfYW5ub19zaXplID0gdW5pdCgxLjUsICJtbSIpLG5hX2NvbCA9IGMoIndoaXRlIiwid2hpdGUiLCJ3aGl0ZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kID0gYyhGQUxTRSxGQUxTRSxGQUxTRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3AgPSBncGFyKGNvbCA9ICJncmV5OTAiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2w9bGlzdChDUERCID0gYygiVFJVRSIgPSAiZ3JleTYwIiwgIkZBTFNFIiA9ICJ3aGl0ZSIsIk5BIiA9ICJ3aGl0ZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEtFR0cgPSBjKCJUUlVFIiA9ICJncmV5NjAiLCAiRkFMU0UiID0gIndoaXRlIiwiTkEiID0gIndoaXRlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5fcGxhc21hID0gYygiVFJVRSIgPSAiZGFya3JlZCIsICJGQUxTRSIgPSAid2hpdGUiLCJOQSIgPSAid2hpdGUiKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd19kZW5kID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X3RpdGxlX3NpZGUgPSAicmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfdGl0bGVfcm90ID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfdGl0bGUgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBzY2FsZWRfMDFfY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fZGVuZF9oZWlnaHQgPSB1bml0KDIsIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd19kZW5kX3dpZHRoID0gdW5pdCgyLCAibW0iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd19kZW5kX3NpZGUgPSAibGVmdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kX2NvbHVtbnMgPSAibWNxdWl0dHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICByaWdodF9hbm5vdGF0aW9uID0gcm93QW5ub3RhdGlvbihkZiA9IGNvbC5hbm5vLmRmICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoImNvbG5hbWVzIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChjb2xhbm5vID0gTDFfY29sb3JzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19hbm5vdGF0aW9uX25hbWUgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2xlZ2VuZCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KC4xLCAiY20iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KC4yLCAiY20iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDEsICJtbSIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd19zcGxpdCA9IGNvbC5hbm5vLmRmJGNvbGFubm8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9NCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl90aXRsZV9yb3QgPSA0NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCgzLCAibW0iKSkpCikKCmBgYAoKCgojIyBTdXBwbGVtYW50YXJ5IEZpZ3VyZSBTNiAKKipyZWxhdGVkIHRvIG1haW4gRmlndXJlIDMqKgoKIyMjIEZpZ3VyZSBTNkEKYGBge3J9CihyaGFwc29keV9jZWxsc19wZXJfc2FtcGxlIDwtIHRpYmJsZShwYm1jQG1ldGEuZGF0YSkgJT4lCiAgI2FzLmRhdGEudGFibGUgJT4lICMgdGhlIHJlc3VsdGluZyBtZCBvYmplY3QgaGFzIG9uZSAicm93IiBwZXIgY2VsbAogIHJvd25hbWVzX3RvX2NvbHVtbigiQ2VsbElEIikgICU+JSAKICBncm91cF9ieShvcmlnLmlkZW50LFRpbWUpICU+JSAKICBkcGx5cjo6Y291bnQoKSAlPiUgCiAgZ2dwbG90KGFlcyh4PW9yaWcuaWRlbnQseT1uLCBmaWxsPVRpbWUpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gVElNRV9jb2xvcnMsYnJlYWtzID0gYygiQWN1dGUiLCJEMTAiLCJZMSIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgdHJhbnMgPSAic3FydCIpICsKICBjb29yZF9mbGlwKCkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZG9kZ2UiLCBzaG93LmxlZ2VuZCA9IFRSVUUpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9NjAwMCxsd2Q9LjIpICsKICBsYWJzKHk9Ik51bWJlciBvZiBjZWxscyIsCiAgICAgICB4PSIiLAogICAgICAgZmlsbD0iIikgKyAKICB0aGVtZV9taW5pbWFsKCkpCmBgYAoKIyMjIEZpZ3VyZSBTNkIKYGBge3J9CiMjIGludGVncmF0aW9uCihyaGFwc29keV91bWFwX2dncGxvdF9pbnRfb3JpZy5pZGVudCA8LSByaGFwc29keV91bWFwX2Nvb3JkcyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gd25uVU1BUF8xLCB5ID0gd25uVU1BUF8yKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGFzLmNoYXJhY3RlcihvcmlnLmlkZW50KSksIHNpemUgPSAwLjEsIGFscGhhPS4xKSArCiAgbGFicyh4ID0gJ3dublVNQVAgMScsIHkgPSAnd25uVU1BUCAyJywgY29sb3I9TlVMTCkgICsgCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAxLHNpemU9LjI1KSkpICsKICBteV9kaW1yZWRfdGhlbWUKKQpgYGAKCiMjIyBGaWd1cmUgUzZDCmBgYHtyIH0KIyMgaW50ZWdyYXRpb24KKHJoYXBzb2R5X3VtYXBfZ2dwbG90X2ludF90aW1lIDwtIHJoYXBzb2R5X3VtYXBfY29vcmRzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB3bm5VTUFQXzEsIHkgPSB3bm5VTUFQXzIpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gYXMuY2hhcmFjdGVyKFRpbWUpKSwgc2l6ZSA9IDAuMjUsIGFscGhhPS4xKSArCiAgbGFicyh4ID0gJ3dublVNQVAgMScsIHkgPSAnd25uVU1BUCAyJywgY29sb3I9TlVMTCkgICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IFRJTUVfY29sb3JzLGJyZWFrcyA9IGMoIkFjdXRlIiwiRDEwIiwiWTEiKSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhID0gMSxzaXplPS4yNSkpKSArCiAgbXlfZGltcmVkX3RoZW1lCikKYGBgCgojIyMgRmlndXJlIFM2RApgYGB7cn0KKHZsbl9hZHQud2VpZ2h0IDwtIFZsblBsb3QocGJtYywgZmVhdHVyZXMgPSAiYWR0LkNDQS53ZWlnaHQiLCBncm91cC5ieSA9ICdDZWxsVHlwZV9MMicsIGNvbHMgPSBMMl9jb2xvcnMsIHNvcnQgPSBUUlVFLCBwdC5zaXplID0gMCkgKwogIE5vTGVnZW5kKCkgKyAKICBsYWJzKHRpdGxlID0gImFkdCB3ZWlnaHQiLCB5PSJBRFQgd2VpZ2h0Iix4PU5VTEwpKQpgYGAKCiMjIyBGaWd1cmUgUzZFCmBgYHtyfQpybmEubWFya2VyNGRvdHBsb3QgPC0gYygiUzEwMEExMiIsIkNEMTQiLCJTMTAwQTkiLCJWTU8xIiwiQzFRQSIsIkZDR1IzQSIsICJLTFJGMSIsIktJUjJETDEiLAogICAgICAgICAgICAgICAgICAgICAgICAiR05MWSIsIklMMTJSQjIiLCJJTDE4UjEiLCJHWk1LIiwiVFlNUyIsIlRPUDJBIiwgIktJQUEwMTAxIiwiQ0NSNyIsIkxFRjEiLAogICAgICAgICAgICAgICAgICAgICAgICAiTVlDIiwgIlBBU0siLCJDRDI4IiwiSUNPUyIsIlJHUzEiLCJDVExBNCIsIkNDUjUiLCJMQUczIiwiUE9VMkFGMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICJGT1hQMyIsIklMMlJBIiwiQ0Q4QSIsIlpORjY4MyIsIlJPUkMiLCJJS1pGMiIsIk1TNEExIiwiQ0Q3OUEiLCJJR0tDIiwKICAgICAgICAgICAgICAgICAgICAgICAgIlRDTDFBIiwiRkNFUjIiLCJDRDIwMCIsIlRORlJTRjE3IiwiRkNFUjFBIiwiQ0xFQzEwQSIsIkNEMUMiLCJOUlAxIiwiVExSOSIsIlRMUjciKQoKKGRvdHBsb3Qucm5hIDwtIERvdFBsb3QocGJtYywKICAgICAgICBmZWF0dXJlcyA9IHJuYS5tYXJrZXI0ZG90cGxvdCwKICAgICAgICBhc3NheSA9ICJSTkEiLAogICAgICAgIGNvbHMgPSBjKCJSZFlsQnUiKSwKICAgICAgICBjb2wubWluID0gLTIuNSwKICAgICAgICBjb2wubWF4ID0gMi41LAogICAgICAgIGRvdC5taW4gPSAwLAogICAgICAgIGRvdC5zY2FsZSA9IDEsCiAgICAgICAgaWRlbnRzID0gTlVMTCwKICAgICAgICBncm91cC5ieSA9IE5VTEwsCiAgICAgICAgc3BsaXQuYnkgPSBOVUxMLAogICAgICAgIGNsdXN0ZXIuaWRlbnRzID0gRiwKICAgICAgICBzY2FsZSA9IFRSVUUsCiAgICAgICAgc2NhbGUuYnkgPSAicmFkaXVzIiwKICAgICAgICBzY2FsZS5taW4gPSBOQSwKICAgICAgICBzY2FsZS5tYXggPSBOQSkgKyAKICBSb3RhdGVkQXhpcygpICsgCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSkgKyAKICBsYWJzKHg9IiIseT0iIiwgdGl0bGU9Im1STkEgZXhwcmVzc2lvbiIpCikKYGBgCgoKYGBge3J9CkRvdFBsb3QocGJtYywKICAgICAgICBmZWF0dXJlcyA9IHJvd25hbWVzKHBibWNAYXNzYXlzJEFEVCksCiAgICAgICAgYXNzYXkgPSAiQURUIiwKICAgICAgICBjb2xzID0gYygiUmRZbEJ1IiksCiAgICAgICAgY29sLm1pbiA9IC0yLjUsCiAgICAgICAgY29sLm1heCA9IDIuNSwKICAgICAgICBkb3QubWluID0gMCwKICAgICAgICBkb3Quc2NhbGUgPSAxLAogICAgICAgIGlkZW50cyA9IE5VTEwsCiAgICAgICAgZ3JvdXAuYnkgPSBOVUxMLAogICAgICAgIHNwbGl0LmJ5ID0gTlVMTCwKICAgICAgICBjbHVzdGVyLmlkZW50cyA9IEYsCiAgICAgICAgc2NhbGUgPSBUUlVFLAogICAgICAgIHNjYWxlLmJ5ID0gInJhZGl1cyIsCiAgICAgICAgc2NhbGUubWluID0gTkEsCiAgICAgICAgc2NhbGUubWF4ID0gTkEpICsgCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksICMgY2VsbCBzdWJzZXRzCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYpKSArIAogIFJvdGF0ZWRBeGlzKCkgKwogIGxhYnMoeD0iIix5PSIiLCB0aXRsZT0iU3VyZmFjZSBwcm90ZWluIGV4cHJlc3Npb24iKQpgYGAKCiMjIyBGaWd1cmUgUzZGCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CihjZWxsbnVtYmVyc19sMiA8LSB0aWJibGUocGJtY19hY3V0ZUBtZXRhLmRhdGEpICU+JSAKICAgZ3JvdXBfYnkoQ2VsbFR5cGVfTDIpICU+JSAKICAgY291bnQoKSAlPiUgCiAgIAogICBnZ3Bsb3QoYWVzKGZpbGwgPSBDZWxsVHlwZV9MMiwgeT1uLCB4PWZjdF9yZW9yZGVyKENlbGxUeXBlX0wyLG4pKSkgKyAKICAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGKSArCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IEwyX2NvbG9ycykgKwogICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSx0cmFucyAgPSAibG9nMTAiLCBicmVha3M9YygxLDEwLDEwMCwxMDAwLDUwMDApKSArIAogICBjb29yZF9mbGlwKCkgKwogICBsYWJzKHg9TlVMTCwKICAgICAgICB5PSJOdW1iZXIgb2YgY2VsbHMiKSArCiAgIHRoZW1lX2J3KCkgKwogICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCkpKQpgYGAKCiMjIyBGaWd1cmUgUzZHCmBgYHtyfQpnZW5lcy5vaS50aW1lcG9pbnRzID0gVmxuUGxvdChwYm1jLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGMoIkNEMTYzIiwgIklMMUIiLCAiSUwxUk4iLCAiSUNBTTEiLCAiTElMUkI0IiwgIkNYQ0wxMCIsICJTMTAwQTEyIiwgICJOQU1QVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0NMMiIsICJDWENMMTEiLCAiQ1hDTDkiLCAiQVpVMSIsIlZNTzEiLCAiVE5GUlNGOCIsICJDSEkzTDEiLCJDQ0w0IiwgIkdaTUEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdaTUIiLCJHWk1IIiwiQ1NUNyIsIlRORlJTRjkiLCJJTDJSQSIsIklMMVJMMSIsIkNENDgiLCAiQ0QyNyIsICJDRDM4IiwgIkhBVkNSMiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICdDZWxsVHlwZV9MMicsIGFzc2F5ID0gIlJOQSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwbGl0LmJ5ID0gIlRpbWUiLCBjb2xzID0gdGltZTNfY29sLCBzb3J0ID0gRiwgcHQuc2l6ZSA9IDAsc3RhY2sgPSBULGZsaXAgPSBGKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBzaXplPTYpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA1LCBmYWNlPU5VTEwsaGp1c3QgPSAuNSksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICMgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAjIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCguMiwgJ2NtJyksICNjaGFuZ2UgbGVnZW5kIGtleSBzaXplCiAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KC4yLCAnY20nKSwgI2NoYW5nZSBsZWdlbmQga2V5IGhlaWdodAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KC4yLCAnY20nKSwgI2NoYW5nZSBsZWdlbmQga2V5IHdpZHRoCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSksICNjaGFuZ2UgbGVnZW5kIHRpdGxlIGZvbnQgc2l6ZQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NSkpCgpnZW5lcy5vaS50aW1lcG9pbnRzJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkc2l6ZSA9IC4xCmdlbmVzLm9pLnRpbWVwb2ludHMKYGBgCgoKIyMgU3VwcGxlbWVudGFyeSBGaWd1cmUgNyAKKipyZWxhdGVkIHRvIG1haW4gRmlndXJlIDMqKgoKYGBge3IgZG9vbGV5LWxvYWQtZGF0YX0KZG9vbGV5IDwtIHJlYWRSRFMoIi4uL2RhdGEvZGF0YS9SZUFuYWx5c2lzX0Rvb2xleU5MX2V0YWxfYmlvUnhpdl8yMDIyL2Fubm90YXRlZF9TYWJhaF9kYXRhXzIxT2N0MjAyMi5yZHMiKQoKZG9vbGV5X2NvbG9ycyA8LSBzZXROYW1lcyhyYW5kb21jb2xvUjo6ZGlzdGluY3RDb2xvclBhbGV0dGUobGVuZ3RoKHVuaXF1ZShkb29sZXlAbWV0YS5kYXRhJGNlbGx0eXBlKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZShkb29sZXlAbWV0YS5kYXRhJGNlbGx0eXBlKSkKIyMgUHJlbGltaW5hcnkgUUMgY2hlY2sKCnRpYmJsZShkb29sZXlAbWV0YS5kYXRhKSAlPiUgIyB0aGUgcmVzdWx0aW5nIG1kIG9iamVjdCBoYXMgb25lICJyb3ciIHBlciBjZWxsCiAgcm93bmFtZXNfdG9fY29sdW1uKCJDZWxsSUQiKSAgJT4lIAogIGdyb3VwX2J5KG9yaWcuaWRlbnQsdGltZXBvaW50LHNhbXBsZS5kYXksSUQpICU+JSAKICBkcGx5cjo6Y291bnQoKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBnZ3Bsb3QoYWVzKHg9ZmN0X3Jlb3JkZXIob3JpZy5pZGVudCwgdGltZXBvaW50KSx5PW4sIGZpbGw9SUQpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsKICBjb29yZF9mbGlwKCkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZG9kZ2UiLCBzaG93LmxlZ2VuZCA9IEYpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBjZWxscyBwZXIgc2FtcGxlIiwKICAgICAgIHg9TlVMTCkgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiMjIyBGaWd1cmUgUzdBCmBgYHtyIGRvb2xleS11bWFwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkb29sZXlfdW1hcF9jb29yZHMgPC0gZGF0YS50YWJsZTo6ZGF0YS50YWJsZShkb29sZXlAbWV0YS5kYXRhLCBFbWJlZGRpbmdzKG9iamVjdCA9IGRvb2xleSwgcmVkdWN0aW9uID0gJ3VtYXAnKSkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigiQ2VsbElEIikgCgpsYWJsZV9kZiA8LSBkb29sZXlfdW1hcF9jb29yZHMgJT4lCiAgZHBseXI6Omdyb3VwX2J5KGNlbGx0eXBlKSAlPiUKICBkcGx5cjo6c2VsZWN0KGNlbGx0eXBlLCBjb250YWlucygiVU1BUCIpKSAlPiUKICBzdW1tYXJpc2VfYWxsKG1lYW4pCgooZG9vbGV5X3VtYXBfZ2dwbG90IDwtIGRvb2xleV91bWFwX2Nvb3JkcyAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIpKSArIAogICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBhcy5jaGFyYWN0ZXIoY2VsbHR5cGUpKSwgc2l6ZSA9IDAuMSwgYWxwaGE9LjUsc2hvdy5sZWdlbmQgPSBGKSArCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YT1sYWJsZV9kZixhZXMoeD1VTUFQXzEseT1VTUFQXzIsIGxhYmVsPWNlbGx0eXBlKSxzaXplPTIpICsKICAgIGxhYnMoeCA9ICdVTUFQIDEnLCB5ID0gJ1VNQVAgMicpICArIAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1kb29sZXlfY29sb3JzKSArCiAgICBteV9kaW1yZWRfdGhlbWUpCgpgYGAKCiMjIyBGaWd1cmUgUzdCCmBgYHtyIGRvb2xleS1yZWFuYWx5c2lzfQojIyBQZXJjZW50YWdlIGNlbGx0eXBlIGluIHNhbXBsZQooZG9vbGV5X3Blcl9zYW1wbGVfcGVyYyA8LSB0aWJibGUoZG9vbGV5QG1ldGEuZGF0YSkgJT4lIAogICBncm91cF9ieSh0aW1lcG9pbnQsb3JpZy5pZGVudCkgJT4lIAogICBjb3VudChjZWxsdHlwZSkgJT4lIAogICAjIFN0YWNrZWQgKyBwZXJjZW50CiAgIGdncGxvdChhZXMoZmlsbCA9IGNlbGx0eXBlLCB5PW4sIHg9b3JpZy5pZGVudCkpICsgCiAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIiwgc3RhdD0iaWRlbnRpdHkiLHdpZHRoID0gMC45KSArCiAgIGZhY2V0X2dyaWQofnRpbWVwb2ludCxzY2FsZXMgPSAiZnJlZV94IixzcGFjZSA9ICJmcmVlX3giKSArCiAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsgCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1kb29sZXlfY29sb3JzKSArCiAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQsZXhwYW5kID0gYygwLDApKSArIAogICBsYWJzKHggPSAiIiwKICAgICAgICB5ID0gIkZyZXF1ZW5jeSIsCiAgICAgICAgZmlsbD0iIikgKwogICB0aGVtZV9taW5pbWFsKCkgKwogICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksCiAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpKSkKYGBgCgoKZ2V0IG9ubHkgYWN1dGUgbWFsYXJpYSBjZWxscyAoRGF5MCkKCmBgYHtyIGRvb2xleS1yZWFuYWx5c2lzLWRheTAtY2VsbG51bWJlcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZG9vbGV5XzAgPC0gc3Vic2V0KGRvb2xleSwgc3Vic2V0PXRpbWVwb2ludD09IkRheTAiKQojLSBSTkEgTm9ybWFsaXphdGlvbgpkb29sZXlfMCA8LSBOb3JtYWxpemVEYXRhKG9iamVjdCA9IGRvb2xleV8wLCBhc3NheSA9ICdSTkEnLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICdMb2dOb3JtYWxpemUnLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCkKYGBgCgojIyMgRmlndXJlIFM3QwoKYGBge3IgZG9vbGV5LXJlYW5hbHlzaXMtZGF5MC1jZWxsbnVtYmVzMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KKGRvb2xleV8wX2NlbGxudW1iZXJzIDwtIAogICB0aWJibGUoZG9vbGV5XzBAbWV0YS5kYXRhKSAlPiUgCiAgIGdyb3VwX2J5KGNlbGx0eXBlKSAlPiUgCiAgIGNvdW50KCkgJT4lIAogICBnZ3Bsb3QoYWVzKGZpbGwgPSBjZWxsdHlwZSwgeT1uLCB4PWZjdF9yZW9yZGVyKGNlbGx0eXBlLG4pKSkgKyAKICAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGKSArCiAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLHRyYW5zICA9ICJsb2cxMCIpICsKICAgY29vcmRfZmxpcCgpICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWRvb2xleV9jb2xvcnMpICsKICAgbGFicyh4PU5VTEwsCiAgICAgICAgeT0iTnVtYmVyIG9mIGNlbGxzIikgKwogICB0aGVtZV9idygpICsKICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKSkKYGBgCgpgYGB7ciBkb29sZXktcmVhbmFseXNpcy1kYXkwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyBjYWxjdWxhdGlvbiBvZiBwc2V1ZG9idWxrLCBmb3IgZWFjaCBpZGVudGl0eSBiYXNlZCBvbiBjb3VudCBkYXRhCmRvb2xleV8wLmF2Zy53aWRlIDwtIGxvZzFwKEF2ZXJhZ2VFeHByZXNzaW9uKGRvb2xleV8wLCBncm91cC5ieSA9ICJjZWxsdHlwZSIsIHNsb3QgPSAiY291bnRzIiwgdmVyYm9zZSA9IEZBTFNFKSRSTkEpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigiZ2VuZSIpIAoKZG9vbGV5XzAuYXZnLmxvbmcgPC0gZG9vbGV5XzAuYXZnLndpZGUgJT4lIAogIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJjZWxsdHlwZSIsIHZhbHVlc190byA9ICJhdmdFeHAiLGNvbHMgPSAtZ2VuZSkgJT4lIGZpbHRlcihhdmdFeHAgPjApCmBgYAoKYGBge3J9CmRvb2xleS5nZW5lLm1hdGNoIDwtIGZ1bGxfbWFwcGluZyAlPiUgCiAgZmlsdGVyKFVuaVByb3QgJWluJSB3aWxjb3hVcCkgJT4lIAogIGZpbHRlcihTeW1ib2wgJWluJSB1bmlxdWUoZG9vbGV5XzAuYXZnLmxvbmckZ2VuZSkpCgptYXRfZG9vbGV5XzAgPC0gZG9vbGV5XzAuYXZnLndpZGUgJT4lIAogIGZpbHRlcihnZW5lICVpbiUgZG9vbGV5LmdlbmUubWF0Y2gkU3ltYm9sKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJnZW5lIikgJT4lIAogIGFzLm1hdHJpeCgpIApgYGAKCiMjIyBGaWd1cmUgUzdECmBgYHtyfQojIyBSaGFwc29keSB2cy4gRG9vbGV5CiMjYmlubmluZyBvZiBjZWxsIGltbXVuZSBjZWxsIHN1YnNldHMKCiNkaW0obWF0X2Rvb2xleV8wKQojZGltKG1hdF9wYm1jX2FjdXRlKQoKIyMgZ2VuZSBvdmVybGFwIFJoYXBzb2R5LCBEb29sZXkgZXQgYWwsIEV4cGxvcmUKcmhhcHNvZHlfZG9vbGV5X292ZXJsYXBwIDwtIGludGVyc2VjdChyb3duYW1lcyhtYXRfZG9vbGV5XzApLHJvd25hbWVzKG1hdF9wYm1jX2FjdXRlKSkKCmNvbXBhcmVfZG9vbGV5X3JoYXBzb2R5IDwtIGRhdGEuZnJhbWUobWF0X2Rvb2xleV8wW3JoYXBzb2R5X2Rvb2xleV9vdmVybGFwcCxdKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJnZW5lIikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtZ2VuZSkgJT4lCiAgbXV0YXRlKG9yaWdpbiA9ICJkb29sZXkiKSAlPiUgCiAgYmluZF9yb3dzKAogICAgZGF0YS5mcmFtZShtYXRfcGJtY19hY3V0ZVtyaGFwc29keV9kb29sZXlfb3ZlcmxhcHAsXSkgJT4lIAogICAgICByb3duYW1lc190b19jb2x1bW4oImdlbmUiKSAlPiUgCiAgICAgIHBpdm90X2xvbmdlcihjb2xzID0gLWdlbmUpICU+JQogICAgICBtdXRhdGUob3JpZ2luID0gInJoYXBzb2R5IikpICU+JQogIAogIAogIG11dGF0ZShuYW1lLmNvbW1vbiA9IGlmZWxzZShncmVwbCgiQ0QxNCIsbmFtZSksIkNEMTRtb25vIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJDRDE2Lm1vbm9jeXRlcyIsbmFtZSxpZ25vcmUuY2FzZSA9IFQpLCJDRDE2bW9ubyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoInBEQyIsbmFtZSksInBEQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJtREMiLG5hbWUpLCJtREMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIk5LVCIsbmFtZSksIk5LVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoImdkVHzOs860LlQuY2VsbHMiLG5hbWUpLCJnZFRjZWxsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkNEOCIsbmFtZSksIkNEOFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkNENCIsbmFtZSksIkNENFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJOSyIsbmFtZSksIk5LIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkIiLG5hbWUpLCJCY2VsbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiVW5rbm93bnx1bmRlZmluZWQiLG5hbWUpLCJ1bmRlZmluZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSkpKSkpKSkpKSkpKSAKCmBgYAoKCgpgYGB7cn0KY29tbW9uLmNlbGx0eXBlcyA8LSBpbnRlcnNlY3QoZmlsdGVyKGNvbXBhcmVfZG9vbGV5X3JoYXBzb2R5LG9yaWdpbj09ImRvb2xleSIpICU+JSBwdWxsKG5hbWUuY29tbW9uKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGNvbXBhcmVfZG9vbGV5X3JoYXBzb2R5LG9yaWdpbj09InJoYXBzb2R5IikgJT4lIHB1bGwobmFtZS5jb21tb24pKQoKZG9vbGV5X2htIDwtIGNvbXBhcmVfZG9vbGV5X3JoYXBzb2R5ICU+JSAKICBmaWx0ZXIob3JpZ2luPT0iZG9vbGV5IiwgbmFtZS5jb21tb24gJWluJSBjb21tb24uY2VsbHR5cGVzKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGdlbmUsIHZhbHVlc19mcm9tID0gdmFsdWUsaWRfY29scyA9IG5hbWUuY29tbW9uKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJuYW1lLmNvbW1vbiIpICU+JSAKICAjIyBzY2FsZSB2YWx1ZXMgZnJvbSAwLTEKICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiBzY2FsZXM6OnJlc2NhbGUoLiwgdG89YygwLDEpKSkpICU+JSAKICAgIGFzLm1hdHJpeCgpICU+JSAKICAgIHQoKSAlPiUKCiAgSGVhdG1hcChuYW1lPSJEb29sZXkiLAogICAgICAgICAgY29sdW1uX3RpdGxlID0gIkRvb2xleSBldCBhbC4iLAogICAgICAgICAgY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZT02KSwKICAgICAgICAgIAogICAgICAgICAgY29sdW1uX29yZGVyID0gY29tbW9uLmNlbGx0eXBlcywKICAgICAgICAgIGNvbCA9IHNjYWxlZF8wMV9jb2wsCiAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICAgcm93X2RlbmRfcmVvcmRlciA9IFRSVUUsCiAgICAgICAgICBzaG93X3Jvd19uYW1lcyA9IFRSVUUsCiAgICAgICAgICBzaG93X2hlYXRtYXBfbGVnZW5kID0gRiwKICAgICAgICAgIHJvd190aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwKICAgICAgICAgIHJvd190aXRsZV9yb3QgPSAwLAogICAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDQpLAogICAgICAgICAgcm93X2RlbmRfd2lkdGggPSB1bml0KDUsICJtbSIpLCAKICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwgCiAgICAgICAgICBjb2x1bW5fbmFtZXNfcm90ID0gOTAsCiAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpKSwKICAgICAgICAgIHdpZHRoID0gbnJvdyguKSp1bml0KC4zLCAibW0iKSwgCiAgICAgICAgICBoZWlnaHQgPSBuY29sKC4pKnVuaXQoNiwgIm1tIiksCiAgKQoKcmhhcHNvZHlfaG0gPC0gZmlsdGVyKGNvbXBhcmVfZG9vbGV5X3JoYXBzb2R5LCBvcmlnaW49PSJyaGFwc29keSIsIG5hbWUuY29tbW9uICVpbiUgY29tbW9uLmNlbGx0eXBlcykgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGdlbmUsIHZhbHVlc19mcm9tID0gdmFsdWUsaWRfY29scyA9IG5hbWUuY29tbW9uLHZhbHVlc19mbiA9IG1lZGlhbikgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygibmFtZS5jb21tb24iKSAlPiUgCiAgIyMgc2NhbGUgdmFsdWVzIGZyb20gMC0xCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gc2NhbGVzOjpyZXNjYWxlKC4sIHRvPWMoMCwxKSkpKSAlPiUgI3NjYWxlKC4pKSkgJT4lIAogICAgYXMubWF0cml4KCkgJT4lIAogICAgdCgpICU+JQoKICBIZWF0bWFwKG5hbWU9ImF2ZXJhZ2VcbmdlbmVcbmV4cHJlc3Npb24iLAogICAgICAgICAgY29sdW1uX3RpdGxlID0gIlRoaXMgc3R1ZHkiLAogICAgICAgICAgY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZT02KSwKICAgICAgICAgIGNvbHVtbl9vcmRlciA9IGNvbW1vbi5jZWxsdHlwZXMsCiAgICAgICAgICBjb2wgPSBzY2FsZWRfMDFfY29sLAogICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgIHJvd19kZW5kX3Jlb3JkZXIgPSBUUlVFLAogICAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBUUlVFLAogICAgICAgICAgcm93X3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgcm93X3RpdGxlX3JvdCA9IDAsCiAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNCksCiAgICAgICAgICByb3dfZGVuZF93aWR0aCA9IHVuaXQoNSwgIm1tIiksIAogICAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLCAKICAgICAgICAgIGNvbHVtbl9uYW1lc19yb3QgPSA5MCwKICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3Bvc2l0aW9uID0gInRvcGNlbnRlciIKICAgICAgICAgICksCiAgICAgICAgICB3aWR0aCA9IG5yb3coLikqdW5pdCguMywgIm1tIiksIAogICAgICAgICAgaGVpZ2h0ID0gbmNvbCguKSp1bml0KDYsICJtbSIpLAogICkKCmNvbXBhcmVfZG9vbGV5X3JoYXBzb2R5X2htX25ldyA8LSBkb29sZXlfaG0gKyByaGFwc29keV9obQoKZHJhdyhjb21wYXJlX2Rvb2xleV9yaGFwc29keV9obV9uZXcsIHJvd19kZW5kX3NpZGUgPSAibGVmdCIsIG1haW5faGVhdG1hcCA9ICJhdmVyYWdlXG5nZW5lXG5leHByZXNzaW9uIixhdXRvX2FkanVzdCA9IEYpCgpgYGAKCgojIyMgRmlndXJlIFM3RQpgYGB7cn0KZGltKG1hdF9kb29sZXlfMCkKCnJvdy5hbm5vLmRmIDwtIGRhdGEuZnJhbWUoQXNzYXkgPSByb3duYW1lcyhtYXRfZG9vbGV5XzApKSAlPiUgCiAgbGVmdF9qb2luKGRhcC5yZXMsYnk9YygiQXNzYXkiKSkgJT4lIAogIGxlZnRfam9pbihocGFfMjQuMCxieT1jKCJBc3NheSI9ImdlbmUiKSkgJT4lIAogIG11dGF0ZShzZWNyZXRvbWVfZnVuY3Rpb24gPSBpZmVsc2UoaXMubmEoc2VjcmV0b21lX2Z1bmN0aW9uKSwiTm90IHNlY3JldGVkIiwgc2VjcmV0b21lX2Z1bmN0aW9uKSkgJT4lIAogIGZpbHRlcihzZWNyZXRvbWVfZnVuY3Rpb24gIT0gIk5vdCBzZWNyZXRlZCIpCgpyb3dBbm5vIDwtIEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gcm93LmFubm8uZGYgJT4lIHRyYW5zbXV0ZShBc3NheSxzZWNyZXRvbWVfbG9jYXRpb24pICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoIkFzc2F5IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2ggPSAicm93IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19sZWdlbmQgPSBjKFRSVUUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2Fubm90YXRpb25fbmFtZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9uYW1lX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kX3BhcmFtID0gbGlzdCh0aXRsZSA9ICJIUEFcbmNsYXNzaWZpY2F0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDEsICJtbSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JpZF93aWR0aCA9IHVuaXQoMywgIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3Bvc2l0aW9uID0gInRvcGxlZnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBsaXN0KHNlY3JldG9tZV9sb2NhdGlvbiA9IHNlY3JldG9tZV9sb2NhdGlvbl9jb2xzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaW1wbGVfYW5ub19zaXplID0gdW5pdCgzLCAibW0iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYV9jb2wgPSAiZ3JleTkwIikKCihkb29sZXlfZGF5MF9obS5ocGEubWFwcGluZyA8LSBtYXRfZG9vbGV5XzBbcm93LmFubm8uZGYkQXNzYXksXSAlPiUgCiAgICB0KCkgJT4lIAogICAgIyMgc2NhbGUgdmFsdWVzIGZyb20gMC0xCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gc2NhbGVzOjpyZXNjYWxlKC4sIHRvPWMoMCwxKSkpKSAlPiUgCiAgICBhcy5tYXRyaXgoKSAlPiUgCiAgICB0KCkgJT4lIAogICAgQ29tcGxleEhlYXRtYXA6OkhlYXRtYXAoCiAgICAgIG5hbWU9ImF2ZXJhZ2VcbmdlbmVcbmV4cHJlc3Npb25cbiIsCiAgICAgIGNvbCA9IHNjYWxlZF8wMV9jb2wsCiAgICAgIHJpZ2h0X2Fubm90YXRpb24gPSByb3dBbm5vLAogICAgICBjb2x1bW5fZGVuZF9oZWlnaHQgPSB1bml0KDIsICJtbSIpLCAKICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgcm93X2RlbmRfcmVvcmRlciA9IFRSVUUsCiAgICAgIHNob3dfcm93X25hbWVzID0gVFJVRSwKICAgICAgcm93X3NwbGl0ID0gcm93LmFubm8uZGYkc2VjcmV0b21lX2Z1bmN0aW9uLAogICAgICByb3dfdGl0bGVfc2lkZSA9ICJyaWdodCIsCiAgICAgIHJvd190aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwKICAgICAgcm93X3RpdGxlX3JvdCA9IDAsCiAgICAgIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA0KSwKICAgICAgcm93X2RlbmRfd2lkdGggPSB1bml0KDQsICJtbSIpLCAKICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLCAKICAgICAgY29sdW1uX25hbWVzX3JvdCA9IDkwLAogICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNSkpLAogICAgICBoZWlnaHQgPSBuY29sKC4pKnVuaXQoOCwgIm1tIiksCiAgICAgIHdpZHRoID0gbmNvbCguKSp1bml0KDIsIm1tIikpCikKYGBgCgojIyMgRmlndXJlIFM3RgoKYGBge3J9Cm1hdF9kb29sZXlfMCA8LSBkb29sZXlfMC5hdmcud2lkZSAlPiUgCiAgZmlsdGVyKGdlbmUgJWluJSBkb29sZXkuZ2VuZS5tYXRjaCRTeW1ib2wpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoImdlbmUiKSAlPiUgCiAgYXMubWF0cml4KCkgCgpkaW0obWF0X2Rvb2xleV8wKQoKcm93LmFubm8uZGYgPC0gZGF0YS5mcmFtZShBc3NheSA9IHJvd25hbWVzKG1hdF9kb29sZXlfMCkpICU+JSAKICBsZWZ0X2pvaW4oZGFwLnJlcyxieT1jKCJBc3NheSIpKSAlPiUgCiAgbGVmdF9qb2luKGhwYV8yNC4wLGJ5PWMoIkFzc2F5Ij0iZ2VuZSIpKSAlPiUgCiAgbXV0YXRlKHNlY3JldG9tZV9mdW5jdGlvbiA9IGlmZWxzZShpcy5uYShzZWNyZXRvbWVfZnVuY3Rpb24pLCJOb3Qgc2VjcmV0ZWQiLCBzZWNyZXRvbWVfZnVuY3Rpb24pKSAlPiUgCiAgZmlsdGVyKHNlY3JldG9tZV9mdW5jdGlvbiA9PSAiTm90IHNlY3JldGVkIikKCgooZG9vbGV5X2RheTBfaG0ubm8uaHBhLm1hcHBpbmcgPC0gbWF0X2Rvb2xleV8wW3Jvdy5hbm5vLmRmJEFzc2F5LF0gJT4lIAogICAgdCgpICU+JSAKICAgICMjIHNjYWxlIHZhbHVlcyBmcm9tIDAtMQogICAgYXMuZGF0YS5mcmFtZSgpICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHNjYWxlczo6cmVzY2FsZSguLCB0bz1jKDAsMSkpKSkgJT4lICNzY2FsZSguKSkpICU+JSAKICAgIGFzLm1hdHJpeCgpICU+JSAKICAgIHQoKSAlPiUgCiAgICBDb21wbGV4SGVhdG1hcDo6SGVhdG1hcChuYW1lPSJhdmVyYWdlXG5nZW5lXG5leHByZXNzaW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHNjYWxlZF8wMV9jb2wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2hlYXRtYXBfbGVnZW5kID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl9kZW5kX2hlaWdodCA9IHVuaXQoMiwgIm1tIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd19kZW5kX3Jlb3JkZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X3NwbGl0ID0gcm93LmFubm8uZGYkc2VjcmV0b21lX2Z1bmN0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X3RpdGxlX3NpZGUgPSAicmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X3RpdGxlX3JvdCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfZGVuZF93aWR0aCA9IHVuaXQoNCwgIm1tIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl9uYW1lc19yb3QgPSA5MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gbmNvbCguKSp1bml0KDgsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSBuY29sKC4pKnVuaXQoMiwibW0iKSkKKQpgYGAKCiMgRmlndXJlIDQKKipQcm90ZWluIHByb2ZpbGUtYmFzZWQgcGF0aWVudCBzdHJhdGlmaWNhdGlvbiBvZiBkaXNlYXNlIHNldmVyaXR5KioKCiMjIFN1cHBsZW1lbnRhcnkgRmlndXJlIDgKKiogcmVsYXRlZCB0byBtYWluIEZpZ3VyZSA0KioKCkZpZ3VyZSBTOEEKYGBge3J9CmNsaW5fbWFya2VyX2NvbHMgPC0gYygiQ1JQIiwiQ3JlYXRpbmluZSIsIlBhcmFzaXRlbWlhIiwiUGxhdGVsZXRzIiwiQmlsaXJ1YmluIiwiQVNBVCIsIkFMQVQiLCJIZW1vZ2xvYmluIikKCmNsaW5fbWFya2VyX2NvbHMgPC0gc2V0TmFtZXMoYnJld2VyLnBhbChsZW5ndGgoY2xpbl9tYXJrZXJfY29scyksbmFtZT0iU2V0MyIpLCBjbGluX21hcmtlcl9jb2xzKQoKCgpjbGluaWNhbF92YXJpYWJsZXNfNGNpcmNvcyA8LSAgc3ViamVjdFRhYmxlICU+JSAKICAgIGxlZnRfam9pbihjbGluY2hlbV9zdHVkeV9wYXRzX2FjdXRlLndpZGUsIGJ5PSJzdHVkeV9pZCIpICU+JSAKICAgICNpbm5lcl9qb2luKHBhdGllbnRfY2x1c3QsYnk9InN0dWR5X2lkIikgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIHBpdm90X2xvbmdlcihjb2xzID0gYyhwbHRfY291bnRfbWluLGluZl9yYmNfbWF4LGNycF9tYXgsaGJfbWluLGJpbGlfbWF4LGNyZWFfbWF4LCJwX2FsYXQiLCJwX2FzYXQiKSwKICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJjbGluLnZhciIsIHZhbHVlc190bz0iY2xpbi52YWwiLAogICAgKSAlPiUgCiAgICBkcm9wX25hKGNsaW4udmFsKSAlPiUgCiAgICBncm91cF9ieShjbGluLnZhcikgJT4lIAogbXV0YXRlKG5fZ3JvdXA9IGFzLmNoYXJhY3RlcihuKCkpLAogICAgICAgICAgIGxhYmVsX2dyb3VwPSBmYWN0b3IocGFzdGUwKCdcbiBuID0gJywgbl9ncm91cCkpKSAlPiUgCiAgICBtdXRhdGUoY2xpbi52YXIgPSBjYXNlX3doZW4oY2xpbi52YXI9PSJjcnBfbWF4In4iQ1JQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjbGluLnZhcj09InBfYWxhdCJ+IkFMQVQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNsaW4udmFyPT0icF9hc2F0In4iQVNBVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpbi52YXI9PSJwbHRfY291bnRfbWluIn4iUGxhdGVsZXRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjbGluLnZhcj09ImluZl9yYmNfbWF4IiB+IlBhcmFzaXRlbWlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjbGluLnZhcj09ImJpbGlfbWF4In4iQmlsaXJ1YmluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjbGluLnZhcj09ImhiX21pbiIgfiJIZW1vZ2xvYmluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjbGluLnZhcj09ImNyZWFfbWF4In4iQ3JlYXRpbmluZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQ9Y2xpbi52YXIpKSAlPiUgCiAgICBtdXRhdGUoY2xpbi52YXIgPSBmYWN0b3IoY2xpbi52YXIsIGxldmVscz1uYW1lcyhjbGluX21hcmtlcl9jb2xzKSkpIAogCihjbGluX3BhcmFfd2hvbGVfY29ob3J0IDwtIGNsaW5pY2FsX3ZhcmlhYmxlc180Y2lyY29zICU+JSAKICAgIGdncGxvdChhZXMoeD1sYWJlbF9ncm91cCwgeT1jbGluLnZhbCwgZmlsbD1jbGluLnZhcikpICsKICAgIGdlb21fdmlvbGluKHRyaW09Riwgc2hvdy5sZWdlbmQgPSBGLCB3aWR0aD0uNCxsd2Q9LjI1KSArCiAgICBnZW9tX2ppdHRlcihzaXplPTAuMDUsd2lkdGggPSAuMSwgc2hvdy5sZWdlbmQgPSBGLGx3ZD0uMjUpICsKICAgIGdlb21fYm94cGxvdChhbHBoYT0uNywgb3V0bGllci5zaGFwZSA9IE5BLCB3aWR0aD0uMiwgc2hvdy5sZWdlbmQgPSBGLGx3ZD0uMjUpICsKICAgIGZhY2V0X3dyYXAofmNsaW4udmFyLCBzY2FsZXMgPSAiZnJlZSIsIG5yb3cgPSA0LAogICAgbGFiZWxsZXIgPSBsYWJlbGxlcihjbGluLnZhciA9IGMoIkJpbGlydWJpbiI9ICJCaWxpcnViaW5cbihcVTAwM0JDbW9sL0wpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBTEFUIj0iQUxUXG4oVS9MKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQVNBVCI9IkFTVFxuKFUvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNSUCI9IkNSUFxuKG1nL0wpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQYXJhc2l0ZW1pYSI9IlBhcmFzaXRlbWlhXG4oJSkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDcmVhdGluaW5lIj0iQ3JlYXRpbmluZVxuKFxVMDAzQkNtb2wvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhlbW9nbG9iaW4iPSJIZW1vZ2xvYmluXG4oZy9kTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBsYXRlbGV0cyI9IlBsYXRlbGV0XG4oY291bnRzKSIpKSkgKwogICAgdGhlbWVfYncoYmFzZV9zaXplID0gNikrCiAgICBsYWJzKHk9IkNsaW5pY2FsIHBhcmFtZXRlciB2YWx1ZSIsCiAgICAgICAgIHg9TlVMTCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jbGluX21hcmtlcl9jb2xzKSkKCiAKYGBgCgojIyMgRmlndXJlIFM4QyAKYGBge3J9CnBhdGllbnRfU09GQSA8LSBzdWJqZWN0VGFibGUgJT4lIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfaWQsIGNvbnRhaW5zKCJTT0ZBIikpCgp3aG8yMl9zZXZlcmVtYWxhcmlhIDwtIHN1YmplY3RUYWJsZSAlPiUgCiAgdHJhbnNtdXRlKHN0dWR5X2lkLAogICAgICAgICAgICByZXNwaXJhdG9yeV9kaXN0cmVzcyA9IGNhc2Vfd2hlbihwdWxtX2VkZW1hID09IDEgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BfZGlzdHJlc3MgPT0gMSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJkcyA9PSAxIH4gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gMCksCiAgICAgICAgICAgIGNpcmNfODAsCiAgICAgICAgICAgIGhiXzcwID0gY2FzZV93aGVuKGhiX21pbiA8PSA3MCB+IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYl9taW4gPjcwIH4wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BKSwKICAgICAgICAgICAgYmlsaV81MCwKICAgICAgICAgICAgY3JlYV8yNjUgPSBjYXNlX3doZW4oY3JlYV9tYXggPj0gMjY1IH4gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyZWFfbWF4IDwyNjUgfiAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BKSwKICAgICAgICAgICAgcGFyYXNpdGFlbWlhXzIgPSBjYXNlX3doZW4oaW5mX3JiY19tYXggPj0gMiB+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZl9yYmNfbWF4IDwgMiB+IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gTkEpLAogICAgICAgICAgICBwYXJhc2l0YWVtaWFfNSA9IGNhc2Vfd2hlbihpbmZfcmJjX21heCA+PSA1IH4gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mX3JiY19tYXggPCA1IH4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSkKICApCgptYXQgPC0gd2hvMjJfc2V2ZXJlbWFsYXJpYSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9pZCIpICU+JSAKICBhcy5tYXRyaXgoKSAlPiUgCiAgdCgpCgptYXRfc29mYV90b3RhbCA8LSBkYXRhLmZyYW1lKHN0dWR5X2lkID0gY29sbmFtZXMobWF0KSkgJT4lIAogIGxlZnRfam9pbihwYXRpZW50X1NPRkEsIGJ5PSJzdHVkeV9pZCIpIAoKc3R1ZHlfaWRfU09GQS5zb3J0ZWQgPC0gbWF0X3NvZmFfdG90YWwgJT4lIGFycmFuZ2UoLVNPRkFfdG90YWwpICU+JSBwdWxsKHN0dWR5X2lkKQoKbWF0IDwtIG1hdFssc3R1ZHlfaWRfU09GQS5zb3J0ZWRdCgoKc2V2ZXJlc2lnbl9jb3VudCA8LSB3aG8yMl9zZXZlcmVtYWxhcmlhICU+JSAKICB0cmFuc211dGUoc3R1ZHlfaWQsCiAgICAgICAgICAgIHJlc3BpcmF0b3J5X2Rpc3RyZXNzLAogICAgICAgICAgICBjaXJjXzgwLAogICAgICAgICAgICBoYl83MCwKICAgICAgICAgICAgYmlsaV81MCwKICAgICAgICAgICAgY3JlYV8yNjUsCiAgICAgICAgICAgIHBhcmFzaXRhZW1pYV81KSAlPiUgCiAgcmVwbGFjZShpcy5uYSguKSwgMCkgJT4lIAogIHJvd3dpc2UoKSAlPiUKICBtdXRhdGUobnJfb2Zfc2V2ZXJlX3NpZ25zID0gc3VtKGNfYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpKSkpICU+JSAKICB0cmFuc211dGUoc3R1ZHlfaWQsCiAgICAgICAgICAgIG5yX29mX3NldmVyZV9zaWducykgCgooaG0uc29mYS5jbGluIDwtIG1hdCAlPiUgCiAgSGVhdG1hcChuYW1lID0gIlNldmVyZSBtYWxhcmlhIHN5bXB0b21zXG5kZWZpbmVkIGJ5IFdITyAyMDE1IiwKICAgICAgICAgIGNvbCA9IGMoIjAiPSJ3aGl0ZSIsIjEiPSIjQzUxQjdEIiksCiAgICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksIAogICAgICAgICAgbmFfY29sID0gImdyZXk5MCIsCiAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGLAogICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRiwKICAgICAgICAgIHNob3dfcm93X2RlbmQgPSBGLCAKICAgICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGLAogICAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGLAogICAgICAgICAgdG9wX2Fubm90YXRpb24gPSBIZWF0bWFwQW5ub3RhdGlvbihkZiA9IGRhdGEuZnJhbWUoc3R1ZHlfaWQgPSBjb2xuYW1lcyhtYXQpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oc2V2ZXJlc2lnbl9jb3VudCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9pZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3Bvc2l0aW9uID0gInRvcGNlbnRlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJOciBvZlxuc2V2ZXJlIG1hbGFyaWFcbnN5bXB0b21zIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDIsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBsaXN0KG5yX29mX3NldmVyZV9zaWducyA9IGNpcmNsaXplOjpjb2xvclJhbXAyKGMoMCw2KSwgYygid2hpdGUiLCJvcmFuZ2UiKSkpKSwKICAgICAgICAgIHJvd190aXRsZV9zaWRlID0gImxlZnQiLAogICAgICAgICAgcm93X3RpdGxlX3JvdCA9IDAsCiAgICAgICAgICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICBjb2x1bW5fdGl0bGVfc2lkZSA9ICJ0b3AiLAogICAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgcm93X2RlbmRfd2lkdGggPSB1bml0KDAuNSwgImNtIiksIAogICAgICAgICAgY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgY29sdW1uX25hbWVzX3JvdCA9IDkwLAogICAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfcG9zaXRpb24gPSAidG9wY2VudGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdCA9IGMoMCwxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJubyIsInllcyIpKSwKICAgICAgICAgIGJvdHRvbV9hbm5vdGF0aW9uID0gSGVhdG1hcEFubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKHN0dWR5X2lkID0gY29sbmFtZXMobWF0KSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZnRfam9pbihwYXRpZW50X1NPRkEsIGJ5PSJzdHVkeV9pZCIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KC1zdHVkeV9pZCkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2ggPSAnY29sJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwID0gZ3Bhcihmb250c2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcGxlX2Fubm9fc2l6ZSA9IHVuaXQoMiwgIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3QoU09GQV90b3RhbCA9IGNvbG9yUmFtcDIoYyhtaW4ocGF0aWVudF9TT0ZBJFNPRkFfdG90YWwsbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhbihwYXRpZW50X1NPRkEkU09GQV90b3RhbCxuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KHBhdGllbnRfU09GQSRTT0ZBX3RvdGFsLG5hLnJtID0gVFJVRSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoYnJld2VyLnBhbCgzLG5hbWU9IlB1QnUiKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNPRkFfbGl2ZXIgPSBTT0ZBX3N1Yl9jb2wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU09GQV9jbnMgPSBTT0ZBX3N1Yl9jb2wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU09GQV9jb2FnID0gU09GQV9zdWJfY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNPRkFfcmVzcCA9IFNPRkFfc3ViX2NvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTT0ZBX2NhcmRpbyA9IFNPRkFfc3ViX2NvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTT0ZBX3JlbmFsID0gU09GQV9zdWJfY29sKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19sZWdlbmQgPSBjKFQsRixGLEYsRixGKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kX3BhcmFtID0gbGlzdChTT0ZBX3RvdGFsID0gbGlzdCh0aXRsZSA9ICJTT0ZBICh0b3RhbCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9wb3NpdGlvbiA9ICJ0b3BjZW50ZXIiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU09GQV9jbnMgPSBsaXN0KHRpdGxlPSJTT0ZBIChzdWJjYXRlZ29yaWNhbCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfcG9zaXRpb24gPSAidG9wY2VudGVyIikpKSwKICAgICAgICAgIHdpZHRoID0gbmNvbCguKSp1bml0KDEuMywgIm1tIiksIAogICAgICAgICAgaGVpZ2h0ID0gbnJvdyguKSp1bml0KDEuNiwgIm1tIiksCiAgICAgICAgICByZWN0X2dwID0gZ3Bhcihjb2wgPSAiZ3JleTgwIiwgbHdkID0gLjIpLAogICAgICAgICAgYm9yZGVyX2dwID0gZ3Bhcihjb2wgPSAiYmxhY2siLCBsdHkgPSAuNSkpKQoKYGBgCgojIyMgRmlndXJlIFM4RC1FCgoKYGBge3J9CmRhdGE0X3BjYVJlc19GQ21lZGlhbiA8LSBmY19vdmVyX21lZGlhbl9NMTIgJT4lIAogIGZpbHRlcihBc3NheSAlaW4lIGMoZGFwLnJlcyAlPiUgZmlsdGVyKEZEUj09VFJVRSwgYWJzKGxvZ0ZDKT4xKSAlPiUgcHVsbChBc3NheSkpKSAlPiUgCiAgcGl2b3Rfd2lkZXIodmFsdWVzX2Zyb20gPSBkTlBYLCBuYW1lc19mcm9tID0gQXNzYXksIGlkX2NvbHMgPSBzdHVkeV9pZCkgJT4lIGNvbHVtbl90b19yb3duYW1lcygic3R1ZHlfaWQiKSAKCiMjIFBDIGNhbGN1bGF0aW9uCnBjYVJlc19GQ21lZGlhbiA8LSBwcmNvbXAoZGF0YTRfcGNhUmVzX0ZDbWVkaWFuLCBjZW50ZXIgPSBUUlVFLCBzY2FsZS4gPSBUUlVFKQoKdmFyRXhwX0ZDbWVkaWFuIDwtIHJvdW5kKHBjYVJlc19GQ21lZGlhbiRzZGV2XjIgLyBzdW0ocGNhUmVzX0ZDbWVkaWFuJHNkZXZeMikgKiAxMDApCgojc3VtKHZhckV4cF9GQ21lZGlhblsxOjZdKQoKcGNhREZfRkNtZWRpYW4gPC0gZGF0YS5mcmFtZShwY2FSZXNfRkNtZWRpYW4keCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigic3R1ZHlfaWQiKSAlPiUgZHBseXI6OnNlbGVjdCgxOjEwKSAlPiUgCiAgaW5uZXJfam9pbihkYXRhNF9wY2FSZXNfRkNtZWRpYW4gJT4lIHJvd25hbWVzX3RvX2NvbHVtbigic3R1ZHlfaWQiKSwgYnk9InN0dWR5X2lkIikKCihwY2FfRkNtZWRpYW4gPC0gcGNhREZfRkNtZWRpYW4gJT4lIAogICAgZ2dwbG90KGFlcyh4PVBDMSx5PVBDMikpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0uNSkgKyAKICAgIG15X2RpbXJlZF90aGVtZSArCiAgICBjb29yZF9maXhlZChyYXRpbyA9IDEuNzUpICsKICAgIGxhYnMoeD1wYXN0ZTAoIlBDMSAoIix2YXJFeHBfRkNtZWRpYW5bMV0sIiUpIiksCiAgICAgICAgIHk9cGFzdGUwKCJQQzIgKCIsdmFyRXhwX0ZDbWVkaWFuWzJdLCIlKSIpLAogICAgICAgICB0aXRsZSA9ICJkTlBYIChkZWx0YSBOUFggb2YgYWN1dGUgb3ZlciBjb252YWxlc2NlbmNlIG1lZGlhbikiLAogICAgICAgICBjYXB0aW9uID0gcGFzdGUwKCIjIHNhbXBsZXM6ICIsZGltKGRhdGE0X3BjYVJlc19GQ21lZGlhbilbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuICMgcHJvdGVpbnM6ICIsZGltKGRhdGE0X3BjYVJlc19GQ21lZGlhbilbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlxubG9nRkM+MSIpCiAgICApKQoKKGFjdXRlLmRucHguZWxsYm93IDwtIGRhdGEuZnJhbWUoUEMgPSAxOjEwLAogICAgICAgICAgIHZhckV4cCA9IHZhckV4cF9GQ21lZGlhblsxOjEwXSkgJT4lIAogIGdncGxvdChhZXMoeD1QQywgeT12YXJFeHApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAzNSwgYnkgPSA1KSkgKwogIGdlb21fcG9pbnQoc2l6ZT0uMikgKwogIGdlb21fbGluZShsd2Q9LjIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YygxLDEwKSwgYnJlYWtzID0gYygxOjEwKSkpCgpkZiA8LSBwY2FERl9GQ21lZGlhbiAlPiUgCiAgZHBseXI6OnNlbGVjdChzdHVkeV9pZCxQQzE6UEM2KSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9pZCIpIAoKc2V0LnNlZWQoMjAyM0wpCmttIDwtIGttZWFucyhkZiwgY2VudGVycyA9IDMsIG5zdGFydCA9IDI1KSAKCmttLnJlcyA8LSBkYXRhLmZyYW1lKHN0dWR5X2lkID0gcm93bmFtZXMoZGYpKSAlPiUgaW5uZXJfam9pbihkYXRhLmZyYW1lKGNsdXN0ZXIgPSBrbSRjbHVzdGVyKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJzdHVkeV9pZCIpLCBieT0ic3R1ZHlfaWQiKSAKCmBgYAoKCgpgYGB7cn0KcGF0aWVudF9jbHVzdCA8LSBrbS5yZXMgJT4lCiAgaW5uZXJfam9pbihzdWJqZWN0VGFibGUgJT4lIHRyYW5zbXV0ZShzdHVkeV9pZCwgU09GQV90b3RhbCksYnk9InN0dWR5X2lkIikgJT4lIAogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICBzdW1tYXJpc2UobWVhblNPRkFfdG90YWwgPSBtZWFuKFNPRkFfdG90YWwpKSAlPiUgCiAgYXJyYW5nZSgtbWVhblNPRkFfdG90YWwpICU+JSAKICBtdXRhdGUoc2V2ZXJpdHlfbGFiID0gYygic2V2ZXJlIiwibW9kZXJhdGUiLCJtaWxkIikpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oInJvd25hbWUiKSAlPiUgCiAgbXV0YXRlKHJvd25hbWUgPSBhcy5udW1lcmljKHJvd25hbWUpKSAlPiUgCiAgbGVmdF9qb2luKGttLnJlcyAlPiUgdHJhbnNtdXRlKHN0dWR5X2lkLGNsdXN0ZXIpKSAlPiUgCiAgbXV0YXRlKGNsdXN0ZXIub3JpZyA9ICBmY3RfcmVvcmRlcihhcy5mYWN0b3IoY2x1c3Rlcikscm93bmFtZSksCiAgICAgICAgIHNldmVyaXR5X2xhYiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihzZXZlcml0eV9sYWIpLHJvd25hbWUpLAogICAgICAgICBjbHVzdGVyID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKHJvd25hbWUpLHJvd25hbWUpKQoKcGF0aWVudF9jbHVzdCAlPiUgd3JpdGVfdHN2KGZpbGUgPSBwYXN0ZTAocmVzdWx0LmRpciwiUGF0aWVudENsdXN0ZXJpbmcudHN2IikpCnBhdGllbnRfY2x1c3QgJT4lIHNhdmVSRFMoZmlsZSA9IHBhc3RlMChyZXN1bHQuZGlyLCJQYXRpZW50Q2x1c3RlcmluZy5yZHMiKSkKYGBgCgojIyMgRmlndXJlIFM4RC1GCgpgYGB7cn0KcGNhX0ZDbWVkaWFuCmFjdXRlLmRucHguZWxsYm93CgoocGNhREZfRkNtZWRpYW5fUEMxXzZfaG0gPC0gcGNhREZfRkNtZWRpYW4gJT4lIAogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfaWQsUEMxOlBDNikgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic3R1ZHlfaWQiKSAlPiUgCiAgdCgpICU+JSAKICBIZWF0bWFwKG5hbWU9IlBDIHZhbHVlIiwKICAgICAgICAgIGNvbHVtbl9rbSA9IDMsCiAgICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IEYsCiAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgcm93X2RlbmRfd2lkdGggPSB1bml0KDMsICJtbSIpLCAKICAgICAgICAgIGNvbHVtbl9kZW5kX2hlaWdodCA9IHVuaXQoNiwibW0iKSwKICAgICAgICAgIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwgCiAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDEsICJtbSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9wb3NpdGlvbiA9ICJ0b3BjZW50ZXIiKSkKKQpgYGAKCiMjIyBGaWd1cmUgUzhHCmBgYHtyfQpkZl9hY3V0ZV9wYXRjbHVzdF9pbmNsX2NvbnYgPC0gZGF0YS5sb25nICU+JSAKICBpbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgZHBseXI6OnNlbGVjdChEQWlkLFRpbWUsc2FtcGxlX2lkLHN0dWR5X2lkKSxieT0ic2FtcGxlX2lkIikgJT4lIAogIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCxieT0ic3R1ZHlfaWQiKSAlPiUgCiAgCiAgZmlsdGVyKFRpbWU9PSJBY3V0ZSIpICU+JSAKICAjIyBhZGRpbmcgZGF0YSBmb3IgTTEyIHRpbWUgcG9pbnQKICBiaW5kX3Jvd3MoZGF0YS5sb25nICU+JSAKICAgICAgICAgICAgICBpbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgZHBseXI6OnNlbGVjdChEQWlkLFRpbWUsc2FtcGxlX2lkLHN0dWR5X2lkKSxieT0ic2FtcGxlX2lkIikgJT4lIAogICAgICAgICAgICAgIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCxieT0ic3R1ZHlfaWQiKSAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKFRpbWU9PSJNMTIiKSAlPiUgCiAgICAgICAgICAgICAgbXV0YXRlKHNldmVyaXR5X2xhYiA9ICJjb252YWxlc2NlbmNlIikpICU+JSAKICBtdXRhdGUoc2V2ZXJpdHlfbGFiID0gZmFjdG9yKGFzLmZhY3RvcihzZXZlcml0eV9sYWIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPWMoInNldmVyZSIsIm1vZGVyYXRlIiwibWlsZCIsImNvbnZhbGVzY2VuY2UiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJzZXZlcmUiLCJtb2RlcmF0ZSIsIm1pbGQiLCJjb252YWxlc2NlbmNlIikpKSAKYGBgCgoKYGBge3J9Cm15X2NvbXBhcmlzb25zX3NldmVyZV9jb252IDwtIGxpc3QoYygic2V2ZXJlIiwgIm1vZGVyYXRlIiksIGMoIm1vZGVyYXRlIiwgIm1pbGQiKSwgYygic2V2ZXJlIiwgIm1pbGQiKSxjKCJtaWxkIiwiY29udmFsZXNjZW5jZSIpKQoKKGxpdmVyLnRpc3N1ZWxlYWthZ2Uuc2V2ZXJpdHkucGxvdCA8LSBkZl9hY3V0ZV9wYXRjbHVzdF9pbmNsX2NvbnYgJT4lCiAgZmlsdGVyKEFzc2F5ICVpbiUgYygiQUdYVCIsIkhBTzEiKSkgJT4lIAogIGdncGxvdChhZXMoeD1zZXZlcml0eV9sYWIsIHk9TlBYLCBjb2xvcj1zZXZlcml0eV9sYWIsIGZpbGw9c2V2ZXJpdHlfbGFiKSkgKyAKICBnZW9tX3Zpb2xpbih0cmltID0gRixhbHBoYT0uOSkgKwogIGdlb21faml0dGVyKHNpemU9MC4yNSxzaG93LmxlZ2VuZCA9IEYsIHdpZHRoID0gMC4wNSwgYWxwaGE9MSwgY29sb3I9ImdyZXkyMCIpICsKICBnZW9tX2JveHBsb3QoYWxwaGE9Ljcsd2lkdGg9MC4yNSxvdXRsaWVyLnNoYXBlID0gTkEsY29sb3I9ImJsYWNrIiwgZmF0dGVuID0gMixsd2Q9LjI1LHNob3cubGVnZW5kID0gRikgKwogIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAid2lsY294LnRlc3QiLAogICAgICAgICAgICAgICAgICAgICBsYWJlbC5zZXAgPSAiXG4iLAogICAgICAgICAgICAgICAgICAgICBoaWRlLm5zID0gVCwKICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5zaWduaWYiICwKICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAuNSwKICAgICAgICAgICAgICAgICAgICAgc2l6ZT0yLAogICAgICAgICAgICAgICAgICAgICBsd2QgPSAuMiwKICAgICAgICAgICAgICAgICAgICAgY29tcGFyaXNvbnMgPW15X2NvbXBhcmlzb25zX3NldmVyZV9jb252LAogICAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYpICsKICBmYWNldF93cmFwKH5Bc3NheSxuY29sID0gOCxzY2FsZXMgPSAiZnJlZV95IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgbGFicyh4PSIiLAogICAgICAgY29sb3I9TlVMTCwKICAgICAgIGZpbGw9TlVMTCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMocGF0aWVudF9rY2x1c3QzX2xhYl9jb252KSkgKyAKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gYyhwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYpKQopCmBgYAoKCgojIyBGaWd1cmUgNEEKYGBge3J9CihhY3V0ZS5kbnB4LnBjYS5jbHVzdGVyZWQgPC0gcGNhREZfRkNtZWRpYW4gJT4lIAogIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCkgJT4lIAogIGdncGxvdChhZXMoeD1QQzEseT1QQzIsIGNvbG9yPWNsdXN0ZXIpKSArCiAgZ2VvbV9wb2ludChzaXplPS41KSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXBhdGllbnRfa2NsdXN0MykgKwoKICBsYWJzKGNvbG9yPSJDbHVzdGVyIiwKICAgICAgIHRpdGxlPSJkTlBYIikgKwogIGNvb3JkX2VxdWFsKHJhdGlvID0gMS41KSAgKyB0aGVtZV9taW5pbWFsKCkpCgphY3V0ZS5kbnB4LnBjYS5jbHVzdGVyZWQKCgogZ2dFeHRyYTo6Z2dNYXJnaW5hbChhY3V0ZS5kbnB4LnBjYS5jbHVzdGVyZWQsIHR5cGU9ImRlbnNpdHkiLGdyb3VwQ29sb3VyID0gVFJVRSwgZ3JvdXBGaWxsID0gVFJVRSkKYGBgCgoKIyMgRmlndXJlIDRCCmBgYHtyfQoKbXlfY29tcGFyaXNvbnMgPC0gbGlzdChjKCIxIiwgIjIiKSwgYygiMiIsICIzIiksIGMoIjEiLCAiMyIpKQoKKGNsdXN0ZXJzX3NvZmEgPC0gc3ViamVjdFRhYmxlICU+JSAKICAgIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCxieT0ic3R1ZHlfaWQiKSAlPiUgCiAgICAKICAgIGdncGxvdChhZXMoeD1jbHVzdGVyLCB5PVNPRkFfdG90YWwsIGNvbG9yPWNsdXN0ZXIsIGZpbGw9Y2x1c3RlcikpICsKICAgIGdlb21faml0dGVyKHdpZHRoID0gMC4yLHNob3cubGVnZW5kID0gVCwgc2l6ZT0wLjUsYWxwaGE9LjcpICsKICAgIGdlb21fYm94cGxvdChhbHBoYT0xLHdpZHRoPTAuMyxjb2xvcj0iYmxhY2siLG91dGxpZXIuY29sb3VyID0gTkEsIGZhdHRlbiA9IDIsbHdkPS4yNSxzaG93LmxlZ2VuZCA9IEYpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAoIlNlcXVlbnRpYWwgT3JnYW4gRmFpbHVyZSBBc3Nlc3NtZW50IChTT0ZBKSBzY29yZSIpKSArIAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1wYXRpZW50X2tjbHVzdDMpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXBhdGllbnRfa2NsdXN0MykgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxNikpICsKICAgIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAid2lsY294LnRlc3QiLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnNlcCA9ICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgaGlkZS5ucyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5zaWduaWYiICwKICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IC41LAogICAgICAgICAgICAgICAgICAgICAgIHNpemU9MiwKICAgICAgICAgICAgICAgICAgICAgICBsd2QgPSAuMiwKICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9bXlfY29tcGFyaXNvbnMpICsKICAgIHRoZW1lX21pbmltYWwoKSsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9Im5vbmUiKSkKYGBgCgojIyBGaWd1cmUgNEMKYGBge3J9CnByb3QuZGF0YS40LmNvcnIgPC0gZGF0YS5sb25nICU+JQogIGlubmVyX2pvaW4oZGFwLnJlcyxieT1jKCJBc3NheSIsICJVbmlQcm90IikpICU+JSAKICBmaWx0ZXIocC5hZGo8PTAuMDUsCiAgICAgICAgIGFicyhsb2dGQyk+MSwKICApICU+JSAKICBwaXZvdF93aWRlcih2YWx1ZXNfZnJvbSA9IE5QWCwgbmFtZXNfZnJvbSA9IEFzc2F5LGlkX2NvbHMgPSBzYW1wbGVfaWQpICU+JSAKICBpbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgZmlsdGVyKFRpbWU9PSJBY3V0ZSIpICU+JSB0cmFuc211dGUoc2FtcGxlX2lkLHN0dWR5X2lkKSwgYnk9InNhbXBsZV9pZCIpICU+JQogIGRwbHlyOjpzZWxlY3QoLXNhbXBsZV9pZCkgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfaWQsIGV2ZXJ5dGhpbmcoKSkgCgoKY2xpbmljYWwuZmVhdC5saXN0IDwtIGMoImluZl9yYmNfbWF4IiwgInJlc3BfcmF0ZV9tYXgiLCJzYXQiLCAic3lzdF9icF9taW4iLAogICAgICAgICAgICAgICAgICAgICAgICAicF9hbGF0IiwgInBfYXNhdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICJoYl9taW4iLCJ3YmNfY291bnQiLCJwbHRfY291bnRfbWluIiwiY3JwX21heCIsImJpbGlfbWF4IiwiY3JlYV9tYXgiLCJTT0ZBX2NucyIsIlNPRkFfbGl2ZXIiLCJTT0ZBX3JlbmFsIiwiU09GQV9jb2FnIiwiU09GQV9yZXNwIiwiU09GQV90b3RhbCIpCiAgCmNsaW4uZGF0YS40LmNvcnIgPC0KICBzdWJqZWN0VGFibGUgJT4lIAogICAgICBsZWZ0X2pvaW4oY2xpbmNoZW1fc3R1ZHlfcGF0c19hY3V0ZS53aWRlLCBieT0ic3R1ZHlfaWQiKSAlPiUgCgogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfaWQsIGFsbF9vZihjbGluaWNhbC5mZWF0Lmxpc3QpKQoKCm15X2NvbXBhcmlzb25zX3NldmVyZSA8LSBsaXN0KGMoInNldmVyZSIsICJtb2RlcmF0ZSIpLCBjKCJtb2RlcmF0ZSIsICJtaWxkIiksIGMoInNldmVyZSIsICJtaWxkIikpCgpkZiA8LSBjbGluLmRhdGEuNC5jb3JyICU+JSAKICBkcGx5cjo6c2VsZWN0KHN0dWR5X2lkLCBjbGluaWNhbC5mZWF0Lmxpc3QsIC1jb250YWlucygiU09GQSIpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHM9IC1zdHVkeV9pZCkgJT4lIAogIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCkgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZ3JvdXBfYnkobmFtZSwgc2V2ZXJpdHlfbGFiKSAlPiUgCiAgbXV0YXRlKG5fZ3JvdXA9IGFzLmNoYXJhY3RlcihuKCkpLAogICAgICAgICAgICAgICAgICBsYWJlbF9ncm91cD0gZmFjdG9yKHBhc3RlMCgnbiA9ICcsIG5fZ3JvdXApKSkgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShuYW1lKSAlPiUgCiAgIG11dGF0ZShsYWJlbF9wb3MgPSBtaW4odmFsdWUpLAogICAgICAgICAgc3ViY2F0ID0gY2FzZV93aGVuKG5hbWUgJWluJSBjKCJiaWxpX21heCIsICJwX2FsYXQiLCJwX2FzYXQiKSB+ICJMaXZlciBmdW5jdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSAlaW4lIGMoImhiX21pbiIsIndiY19jb3VudCIsICJwbHRfY291bnQiKSB+ICJCbG9vZCBjZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSAlaW4lIGMoInJlc3BfcmF0ZV9tYXgiLCJzYXQiLCJzeXN0X2JwX21pbiIpIH4gIkNpcmN1bGF0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdD1OQSkpICU+JSAKICAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUobmFtZSA9IGZhY3RvcihuYW1lLCBsZXZlbHMgPSBjKCJjcnBfbWF4IiwiY3JlYV9tYXgiLCJpbmZfcmJjX21heCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImhiX21pbiIsIndiY19jb3VudCIsInBsdF9jb3VudF9taW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiaWxpX21heCIsInBfYXNhdCIsInBfYWxhdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJlc3BfcmF0ZV9tYXgiLCJzYXQiLCJzeXN0X2JwX21pbiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSkgCgpzaW5nbGVfZmFjZXRfZnVuID0gZnVuY3Rpb24oZGF0YSkoIAogIGRhdGEgJT4lIAogICAgZ2dwbG90KGFlcyh4PXNldmVyaXR5X2xhYiwgeT12YWx1ZSwgZmlsbD0gc2V2ZXJpdHlfbGFiKSkgKwogICAgZ2VvbV92aW9saW4odHJpbT1GLCBzaG93LmxlZ2VuZCA9IEYsIHdpZHRoPS42LGx3ZD0uMjUpICsKICAgIGdlb21faml0dGVyKHNpemU9MC4wNSx3aWR0aCA9IC4xLCBzaG93LmxlZ2VuZCA9IEYpICsKICAgIGdlb21fYm94cGxvdChhZXMoZmlsbD1zZXZlcml0eV9sYWIpLGFscGhhPS43LCBvdXRsaWVyLnNoYXBlID0gTkEsd2lkdGg9LjIsIHNob3cubGVnZW5kID0gRixsd2Q9LjI1KSArCiAgICB0aGVtZV9idyhiYXNlX3NpemUgPSA2KSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoLjIsMCkpKwogICAgZmFjZXRfZ3JpZCh+bGFiZWxfbmFtZSkgKwogICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGF0aWVudF9rY2x1c3QzX2xhYikgKwogICAgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwuc2VwID0gIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICBoaWRlLm5zID0gVCwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLnNpZ25pZiIsIAogICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgIHNpemU9MiwKICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9IG15X2NvbXBhcmlzb25zX3NldmVyZSkgKwogICAgbGFicyhmaWxsPU5VTEwsCiAgICAgICAgIHg9TlVMTCkgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9ZGF0YSRsYWJlbF9ncm91cCkpCgoKIyMgCnBfbGlzdCA8LSBkZiAlPiUgCiAgbXV0YXRlKG5hbWUgPSBmYWN0b3IobmFtZSwgbGV2ZWxzID0gYygiY3JwX21heCIsImNyZWFfbWF4IiwiaW5mX3JiY19tYXgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJoYl9taW4iLCJ3YmNfY291bnQiLCJwbHRfY291bnRfbWluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmlsaV9tYXgiLCJwX2FzYXQiLCJwX2FsYXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJyZXNwX3JhdGVfbWF4Iiwic2F0Iiwic3lzdF9icF9taW4iCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSksCiAgICAgICAgIGxhYmVsX25hbWUgPSBjYXNlX3doZW4obmFtZSA9PSAiYmlsaV9tYXgiIH4gIkJpbGlydWJpblxuKFxVMDAzQkNtb2wvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImNyZWFfbWF4IiB+ICJDcmVhdGluaW5lXG4oXFUwMDNCQ21vbC9MKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAiY3JwX21heCIgfiAiQ1JQXG4obWcvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImhiX21pbiIgfiAiSGVtb2dsb2JpblxuKGcvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImluZl9yYmNfbWF4IiB+ICJQYXJhc2l0ZW1pYVxuKCUpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJwbHRfY291bnRfbWluIiB+ICJQbGF0ZWxldFxuKGNvdW50cykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInNhdCIgfiAiU2F0dXJhdGlvblxuKCUpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJwX2FzYXQiIH4gIkFTVFxuKFUvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInBfYWxhdCIgfiAiQUxUXG4oVS9MKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAicmVzcF9yYXRlX21heCIgfiAiUmVzcGlyYXRpb25zIHJhdGVcbihicG0pIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJ3YmNfY291bnQiIH4gIldoaXRlIGJsb29kIGNlbGxzXG4oY291bnRzKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAic3lzdF9icF9taW4iIH4gIlN5c3RvbGljIGJsb29kXG5wcmVzc3VyZSAobW1IZykiCiAgICAgICAgICAgICAgICksCiAgICAgICAgIGxhYmVsX3VuaXQgPSBjYXNlX3doZW4obmFtZSA9PSAiYmlsaV9tYXgiIH4gInVuaXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImNyZWFfbWF4IiB+ICJ1bml0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJjcnBfbWF4IiB+ICJtZy9MIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJoYl9taW4iIH4gImcvZEwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImluZl9yYmNfbWF4IiB+ICIlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJwbHRfY291bnRfbWluIiB+ICJjb3VudHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInNhdCIgfiAiJSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAicF9hc2F0IiB+ICJ1bml0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJwX2FsYXQiIH4gInVuaXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInJlc3BfcmF0ZV9tYXgiIH4gImJwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAid2JjX2NvdW50IiB+ICJjb3VudHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInN5c3RfYnBfbWluIiB+ICJtbUhnIgogICAgICAgICAgICAgICApKSAlPiUgCiAgYXJyYW5nZShuYW1lKSAlPiUgCiAgZ3JvdXBfYnkobmFtZSkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKHNpbmdsZV9wbG90ID0gcHVycnI6Om1hcChkYXRhLCBzaW5nbGVfZmFjZXRfZnVuKSkKICAgICAgICAgCgpjbGluLmRhdGEuc2V2ZXJpdHkuZ3JvdXBzLm5ldyA8LSB3cmFwX3Bsb3RzKHBfbGlzdCRzaW5nbGVfcGxvdCwgbmNvbD0zKQoKY2xpbi5kYXRhLnNldmVyaXR5Lmdyb3Vwcy5uZXcuZGF0YSA8LSBwX2xpc3QgJT4lCiAgdW5uZXN0KGRhdGEpICU+JSAKICBjb21wYXJlX21lYW5zKAogICAgdmFsdWUgfiBzZXZlcml0eV9sYWIsIGRhdGEgPSAuLCBncm91cC5ieSA9ICJuYW1lIiwKICAgIG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIpICU+JSAKICB0cmFuc211dGUobmFtZSwgZ3JvdXAxLCBncm91cDIsIHAsIHAuYWRqLCBwLnNpZ25pZiwgbWV0aG9kKSAKCiMjIHNob3cgcGxvdApjbGluLmRhdGEuc2V2ZXJpdHkuZ3JvdXBzLm5ldwpgYGAKCgoKCiMjIEZpZ3VyZSA0RAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgbmVzdCBkYXRhCiNkYXRhX25lc3RlZCA8LSBkYXRhLmxvbmcgJT4lIAojICBpbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSwgYnk9InNhbXBsZV9pZCIpICU+JSAKIyAgbGVmdF9qb2luKHN1YmplY3RUYWJsZSAlPiUgdHJhbnNtdXRlKHN0dWR5X2lkLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9zdXJlID0gZmFjdG9yKGVuZGVtaWMsIGxldmVscz1jKCJwcmltYXJ5X2luZmVjdGVkIiwicHJldmlvdXNseV9leHBvc2VkIikpKSwKIyAgICAgICAgICAgIGJ5PSJzdHVkeV9pZCIpICU+JSAKIyAgZ3JvdXBfYnkoVW5pUHJvdCxBc3NheSkgJT4lIAojICBuZXN0KCkKCiNsbWVfcmVzIDwtIGRhdGFfbmVzdGVkICU+JSAKIyAgbXV0YXRlKGxtZS5yZXMgPSBwdXJycjo6bWFwKGRhdGEsIH4gbG1lcihOUFggfiBUaW1lICogZXhwb3N1cmUgKyAoMXxzdHVkeV9pZCksIFJFTUwgPSBGLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSAueCAlPiUgZHBseXI6OmZpbHRlcihUaW1lIT0iRDEwIikpKSwKIyAgICAgICAgIGxtZS50aWR5ID0gcHVycnI6Om1hcChsbWUucmVzLCB+IGJyb29tLm1peGVkOjp0aWR5KC4pKSwKIyAgICAgICAgIHBvc3Rob2MudGltZSA9IHB1cnJyOjptYXAobG1lLnJlcywgfiBzdW1tYXJ5KGNvbnRyYXN0KGVtbWVhbnMoLiwgfiBUaW1lKSwgbWV0aG9kID0gInBhaXJ3aXNlIikpICU+JSB0aWJibGUoKSksCiMgICAgICAgICBwb3N0aG9jLnRpbWVfZXhwb3N1cmUgPSBwdXJycjo6bWFwKGxtZS5yZXMsIH4gc3VtbWFyeShjb250cmFzdChlbW1lYW5zKC4sIH4gVGltZSAqIGV4cG9zdXJlKSwgbWV0aG9kID0gInBhaXJ3aXNlIikpICU+JSB0aWJibGUoKSkKIyAgICAgICAgICkKCiMjIyMjIwpkYXRhX25lc3RlZC5wYXRjbHVzdCA8LSBkYXRhLmxvbmcgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIAogIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCxieT0ic3R1ZHlfaWQiKSAlPiUgCiAgbXV0YXRlKGFsbF92c18xID0gaWZlbHNlKGNsdXN0ZXIub3JpZyAlaW4lIGMoIjIiLCIzIiksInJlc3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY2x1c3Rlci5vcmlnID09IjEiLCIxIixOQSkpLAogICAgICAgICBhbGxfdnNfMiA9IGlmZWxzZShjbHVzdGVyLm9yaWcgJWluJSBjKCIxIiwiMyIpLCJyZXN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNsdXN0ZXIub3JpZyA9PSIyIiwiMiIsTkEpKSwKICAgICAgICAgYWxsX3ZzXzMgPSBpZmVsc2UoY2x1c3Rlci5vcmlnICVpbiUgYygiMiIsIjEiKSwicmVzdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjbHVzdGVyLm9yaWcgPT0iMyIsIjMiLE5BKSkpICU+JSAKICBncm91cF9ieShVbmlQcm90LEFzc2F5KSAlPiUgCiAgbmVzdCgpCgpnX3ZzX2NvbnYgPC0gZGF0YV9uZXN0ZWQucGF0Y2x1c3QgJT4lCiAgIG11dGF0ZShsbWUucmVzID0gcHVycnI6Om1hcChkYXRhLCB+IGxtZXIoTlBYIH4gVGltZSAqIHNldmVyaXR5X2xhYiArICgxfHN0dWR5X2lkKSwgUkVNTCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gLnggJT4lIGRwbHlyOjpmaWx0ZXIoVGltZSE9IkQxMCIpKSksCiAgICAgICAgIGxtZS50aWR5ID0gcHVycnI6Om1hcChsbWUucmVzLCB+IGJyb29tLm1peGVkOjp0aWR5KC4pKSwKICAgICAgICAgI3Bvc3Rob2MudGltZSA9IHB1cnJyOjptYXAobG1lLnJlcywgfiBzdW1tYXJ5KGNvbnRyYXN0KGVtbWVhbnMoLiwgfiBUaW1lKSwgbWV0aG9kID0gInBhaXJ3aXNlIikpICU+JSB0aWJibGUoKSksCiAgICAgICAgIHBvc3Rob2MudGltZV9leHBvc3VyZSA9IHB1cnJyOjptYXAobG1lLnJlcywgfiBzdW1tYXJ5KGNvbnRyYXN0KGVtbWVhbnMoLiwgfiBUaW1lICogc2V2ZXJpdHlfbGFiKSwgbWV0aG9kID0gInBhaXJ3aXNlIikpICU+JSB0aWJibGUoKSkKICAgICAgICAgKQoKZ192c19jb252X3BhZGogPC0gZ192c19jb252ICU+JSAKICB1bm5lc3QoY29scz0icG9zdGhvYy50aW1lX2V4cG9zdXJlIikgJT4lIAogICNmaWx0ZXIoY29udHJhc3Q9PSJBY3V0ZSBzZXZlcmUgLSBNMTIgc2V2ZXJlIikgJT4lIAogIGZpbHRlcihjb250cmFzdCAlaW4lYygiQWN1dGUgc2V2ZXJlIC0gTTEyIHNldmVyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICJBY3V0ZSBtb2RlcmF0ZSAtIE0xMiBtb2RlcmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICJBY3V0ZSBtaWxkIC0gTTEyIG1pbGQiKSkgJT4lIAogICAgICB0cmFuc211dGUoQXNzYXksIFVuaVByb3QsIGNvbnRyYXN0LCBlc3RpbWF0ZSxTRSxkZix0LnJhdGlvLHAudmFsdWUpICU+JSAKICAjZmlsdGVyKGNvbnRyYXN0PT0iQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIEFjdXRlIHByZXZpb3VzbHlfZXhwb3NlZCIpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogICAgZ3JvdXBfYnkoY29udHJhc3QpICU+JSAKICBtdXRhdGUocC5hZGogPSBwLmFkanVzdChwLnZhbHVlLCBtZXRob2Q9ImZkciIpLAogICAgICAgICAgICAgICAgICBGRFIgPSBpZmVsc2UocC5hZGogPD0gMC4wMSwgVFJVRSxGQUxTRSkpICU+JSAKICAgIHVuZ3JvdXAoKSAlPiUgCiAgYXJyYW5nZShwLmFkaikKCgoKKHNldmVyaXR5X2dyb3Vwc19jb252X3ZvbGMgPC0gZ192c19jb252X3BhZGogJT4lIAogIGdyb3VwX2J5KGNvbnRyYXN0KSAlPiUgCiAgbXV0YXRlKHNldmVyaXR5X2xhYiA9IGNhc2Vfd2hlbihncmVwbCgic2V2ZXJlIixjb250cmFzdCkgfiAic2V2ZXJlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm1vZGVyYXRlIixjb250cmFzdCkgfiAibW9kZXJhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgibWlsZCIsY29udHJhc3QpIH4gIm1pbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BKSwKICAgICAgICAgc2V2ZXJpdHlfbGFiID0gZmFjdG9yKHNldmVyaXR5X2xhYiwgbGV2ZWxzPWMoInNldmVyZSIsIm1vZGVyYXRlIiwibWlsZCIpKSwKICAgICAgICAgc2lnX2NvbCA9IGNhc2Vfd2hlbihGRFI9PVQgfiBzZXZlcml0eV9sYWIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSkpICU+JSAKICAjc2xpY2VfbWF4KG9yZGVyX2J5ID0gZXN0aW1hdGUsIG49MSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PXNldmVyaXR5X2xhYiwgeT0gZXN0aW1hdGUsIGNvbG9yPXNpZ19jb2wpKSArCiAgICBnZW9tX2ppdHRlcih3aWR0aD0uMSxhbHBoYT0uMiwgc2hvdy5sZWdlbmQgPSBGLHNpemU9LjUsIHNoYXBlPTE2KSArCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YT0gLiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShzZXZlcml0eV9sYWIpICU+JSBzbGljZV9tYXgobj04LG9yZGVyX2J5ID0gZXN0aW1hdGUpLCBhZXMobGFiZWw9QXNzYXkpLCBzaG93LmxlZ2VuZCA9IEYsZm9yY2UgPSAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemU9MC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5hbHBoYT0uMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9MS41LG1heC5vdmVybGFwcyA9IDE1LCBjb2xvcj0iZ3JheTM1IikgKwogICAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9IC4gJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoc2V2ZXJpdHlfbGFiKSAlPiUgc2xpY2VfbWluKG49OCxvcmRlcl9ieSA9IGVzdGltYXRlKSwgYWVzKGxhYmVsPUFzc2F5KSwgc2hvdy5sZWdlbmQgPSBGLGZvcmNlID0gLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplPTAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuYWxwaGE9LjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplPTEuNSwgbWF4Lm92ZXJsYXBzID0gMTUsIGNvbG9yPSJncmF5MzUiKSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgCiAgICAgICAgICAgICAgIGxpbmV0eXBlID0gMykgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhdGllbnRfa2NsdXN0M19sYWIsbmEudmFsdWUgPSAiZ3JleSIpICsKICAgIGxhYnMoeD1OVUxMLAogICAgICAgICB0aXRsZT0iRWFjaCBncm91cCB2cyBjb252YWxlY2VuY2UiLAogICAgICAgICBzdWJ0aXRsZSA9ICJtaXhlZCBlZmZlY3QgbW9kZWwgYXBwcm9hY2ggLSBhY3V0ZV9zZXZlcml0eSB2cyBtMTJfc2V2ZXJpdHkiLAogICAgICAgICBjYXB0aW9uPSJGRFIgPCAwLjAxIikpCmBgYAoKIyMgRmlndXJlIDRFCgpgYGB7cn0KcmVxdWlyZShVcFNldFIpICMgaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1VwU2V0Ui92aWduZXR0ZXMvYmFzaWMudXNhZ2UuaHRtbAoKZ192c19jb252X3BhZGpfdG1wLmxpc3QgPC0gZ192c19jb252X3BhZGogJT4lIAogIGdyb3VwX2J5KGNvbnRyYXN0KSAlPiUgCiAgbXV0YXRlKHNldmVyaXR5X2xhYiA9IGNhc2Vfd2hlbihncmVwbCgic2V2ZXJlIixjb250cmFzdCkgfiAic2V2ZXJlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm1vZGVyYXRlIixjb250cmFzdCkgfiAibW9kZXJhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgibWlsZCIsY29udHJhc3QpIH4gIm1pbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BKSwKICAgICAgICAgc2V2ZXJpdHlfbGFiID0gZmFjdG9yKHNldmVyaXR5X2xhYiwgbGV2ZWxzPWMoInNldmVyZSIsIm1vZGVyYXRlIiwibWlsZCIpKSwKICAgICAgICAgc2lnX2NvbCA9IGNhc2Vfd2hlbihGRFI9PVQgfiBzZXZlcml0eV9sYWIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSkpICU+JQogICAgZmlsdGVyKGVzdGltYXRlPjEpICU+JSAKICBncm91cF9ieShzZXZlcml0eV9sYWIpICU+JQogIHN1bW1hcmlzZShsaXN0ID0gbGlzdChBc3NheSkpICU+JQogIG11dGF0ZShsaXN0ID0gc2V0TmFtZXMobGlzdCwgc2V2ZXJpdHlfbGFiKSkgJT4lCiAgcHVsbChsaXN0KQoKc2V2ZXJlX2xvZzEgPC0gaW50ZXJzZWN0KHNldGRpZmYoZ192c19jb252X3BhZGpfdG1wLmxpc3Qkc2V2ZXJlLCBnX3ZzX2NvbnZfcGFkal90bXAubGlzdCRtaWxkKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHNldGRpZmYoZ192c19jb252X3BhZGpfdG1wLmxpc3Qkc2V2ZXJlLCBnX3ZzX2NvbnZfcGFkal90bXAubGlzdCRtb2RlcmF0ZSkpCgpwZGYocGFzdGUwKHJlc3VsdC50bXAuZGlyLCJzZXZlcml0eV9kYXBzX3Vwc2V0LnBkZiIpLHdpZHRoID0gNywgaGVpZ2h0ID0gMykgCihVcFNldFI6OnVwc2V0KGZyb21MaXN0KGdfdnNfY29udl9wYWRqX3RtcC5saXN0KSwKICAgICAgICAgICAgICBvcmRlci5ieSA9ICJmcmVxIixwb2ludC5zaXplID0gMiwKICAgICAgICAgICAgICB0ZXh0LnNjYWxlID0gMS4yLAogICAgICAgICAgICAgI21iLnJhdGlvID0gYygwLjYsIDAuNCksCiAgICAgICAgICAgICAgc2V0cy5iYXIuY29sb3IgPSBjKCJzZXZlcmUiID0gIiNjYTAwMjAiLCJtb2RlcmF0ZSIgPSAiI2Y0YTU4MiIsICJtaWxkIiA9ICIjOTJjNWRlIiksCiAgICAgICAgICAgICAga2VlcC5vcmRlciA9IFRSVUUsCiAgICAgICAgICAgICAgbWFpbmJhci55LmxhYmVsID0gIk51bWJlciBvZiBQcm90ZWlucyIsIAogICAgICAgICAgICAgIHNldHMueC5sYWJlbCA9ICJQcm90ZWlucyBwZXIgZ3JvdXAiKSkKZGV2Lm9mZigpCmBgYAoKCiMjIFN1cHBsZW1lbnRhcnkgVGFibGUgUzMKYGBge3J9CmxpYnJhcnkoZ3RzdW1tYXJ5KQooc2V2ZXJpdHlUYWJsZSA8LSBzdWJqZWN0VGFibGUgJT4lIAogIG11dGF0ZSh3YmNfY291bnQgPSBhcy5udW1lcmljKHdiY19jb3VudCksCiAgICAgICAgIHNhdCA9IGFzLm51bWVyaWMoc2F0KSkgJT4lIAogIGxlZnRfam9pbihwYXRpZW50X2NsdXN0LCBieT0ic3R1ZHlfaWQiKSAlPiUgCiAgICB0Ymxfc3VtbWFyeShpbmNsdWRlID0gYyhpbmZfcmJjX21heCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNycF9tYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaWxpX21heCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyZWFfbWF4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2F0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzcF9yYXRlX21heCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5c3RfYnBfbWluLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGx0X2NvdW50X21pbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhiX21pbiksCiAgICAgICAgICAgICAgYnkgPSBzZXZlcml0eV9sYWIsICMgc3BsaXQgdGFibGUgYnkgZ3JvdXAKICAgICAgICAgICAgICBzdGF0aXN0aWMgPSBsaXN0KAogICAgICAgICAgICAgICAgYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVkaWFufSAoe21pbn0te21heH0pIiwKICAgICAgICAgICAgICAgIGFsbF9jYXRlZ29yaWNhbCgpIH4gIntufSAvIHtOfSAoe3B9JSkiCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICBkaWdpdHMgPSBhbGxfY29udGludW91cygpIH4gMiwKICAgICAgICAgICAgICBtaXNzaW5nX3RleHQgPSAiKE1pc3NpbmcpIikgJT4lIAogIGFkZF9uKCkgJT4lICMgYWRkIGNvbHVtbiB3aXRoIHRvdGFsIG51bWJlciBvZiBub24tbWlzc2luZyBvYnNlcnZhdGlvbnMKICBhZGRfcCgpICU+JSAjIHRlc3QgZm9yIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIGdyb3VwcwogIG1vZGlmeV9oZWFkZXIobGFiZWwgPSAiKipWYXJpYWJsZSoqIikgJT4lICMgdXBkYXRlIHRoZSBjb2x1bW4gaGVhZGVyCiAgYm9sZF9sYWJlbHMoKSkKYGBgCgoKYGBge3J9CnN1YmplY3RUYWJsZSAlPiUgCiAgbXV0YXRlKHdiY19jb3VudCA9IGFzLm51bWVyaWMod2JjX2NvdW50KSwKICAgICAgICAgc2F0ID0gYXMubnVtZXJpYyhzYXQpKSAlPiUgCiAgbGVmdF9qb2luKHBhdGllbnRfY2x1c3QsIGJ5PSJzdHVkeV9pZCIpICU+JSAKICB0cmFuc211dGUoc3R1ZHlfaWQsIAogICAgICAgICAgICBzZXZlcml0eV9sYWIsCiAgICAgICAgICAgIGRpZmZfYWN1dGVTYW1wbGVfdHJlYXRtZW50LGRpZmZfYWN1dGVTYW1wbGVfdHJlYXRtZW50LmFicywKICAgICAgICAgICAgZGlmZl9hY3V0ZVNhbXBsZV9zcHRfY3VycmVudCxkaWZmX2FjdXRlU2FtcGxlX3NwdF9jdXJyZW50LmFicykgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gLWMoc3R1ZHlfaWQsc2V2ZXJpdHlfbGFiKSkgJT4lIAoKY29tcGFyZV9tZWFucygKICAgIHZhbHVlIH4gc2V2ZXJpdHlfbGFiLCBkYXRhID0gLiwgZ3JvdXAuYnkgPSAibmFtZSIsCiAgICBtZXRob2QgPSAid2lsY294LnRlc3QiKQpgYGAKCiMjIFN1cHBsZW1lbWVudGFyeSBUYWJsZSBTNAoKYGBge3J9CiNjbGluLmRhdGEuc2V2ZXJpdHkuZ3JvdXBzLm5ldy5kYXRhICU+JQogIyB3cml0ZV90c3YocGFzdGUwKHJlc3VsdC5kaXIsIlN1cHBsZW1lbnRhcnlfVGFibGVTNF9DbGluaWNhbENoZW1pc3RyeV9zZXZlcml0eV9ncm91cHMudHN2IikpCgpjbGluLmRhdGEuc2V2ZXJpdHkuZ3JvdXBzLm5ldy5kYXRhICU+JSBoZWFkKCkKYGBgCgojIyMgRmlndXJlIFM4QQpgYGB7cn0KcHJvdC5pbnB1dCA8LSBwcm90LmRhdGEuNC5jb3JyICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoInN0dWR5X2lkIikKY2xpbi5pbnB1dCA8LSBjbGluLmRhdGEuNC5jb3JyICU+JSBkcGx5cjo6c2VsZWN0KHN0dWR5X2lkLGMocGx0X2NvdW50X21pbixpbmZfcmJjX21heCxjcnBfbWF4LGhiX21pbixiaWxpX21heCxjcmVhX21heCxwX2FsYXQscF9hc2F0KSkgJT4lICMsY29udGFpbnMoIlNPRkEiKSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9pZCIpCgpjb3IucmVzIDwtIHByb3QuaW5wdXRbcm93bmFtZXMoY2xpbi5pbnB1dCksXSAlPiUgCiAgY29ycmVsYXRpb246OmNvcnJlbGF0aW9uKGRhdGEyID0gY2xpbi5pbnB1dCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gInNwZWFybWFuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZHVuZGFudCA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBwX2FkanVzdCA9ICJmZHIiKSAlPiUgCiAgdGliYmxlKCkKYGBgCgpgYGB7cn0KZGYgPC0gY29yLnJlcyAlPiUKICBmaWx0ZXIobl9PYnMgPj0gMzcsIAogICAgICAgICBwPD0wLjA1LAogICAgICAgICBhYnMocmhvKT49MC40NQogICAgICAgICApICU+JSAKICB0cmFuc211dGUoZnJvbT1QYXJhbWV0ZXIyLCAKICAgICAgICAgICAgdG89UGFyYW1ldGVyMSwKICAgICAgICAgICAgdmFsdWU9cmhvKSAlPiUgCiAgZ3JvdXBfYnkodG8pICU+JSAKICBtdXRhdGUobl9wcm90ID1uKCkpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGdyb3VwX2J5KGZyb20pICU+JSAKICBtdXRhdGUobl9jbGluID0gbigpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBhcnJhbmdlKGRlc2Mobl9wcm90KSxuX2NsaW4pICU+JSAKICAgbXV0YXRlKGZyb20gPSBjYXNlX3doZW4oZnJvbT09ImNycF9tYXgifiJDUlAiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZyb209PSJwX2FsYXQifiJBTFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZyb209PSJwX2FzYXQifiJBU1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZyb209PSJwbHRfY291bnRfbWluIn4iUGxhdGVsZXRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tPT0iaW5mX3JiY19tYXgiIH4iUGFyYXNpdGVtaWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZyb209PSJiaWxpX21heCJ+IkJpbGlydWJpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbT09ImhiX21pbiIgfiJIZW1vZ2xvYmluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tPT0iY3JlYV9tYXgifiJDcmVhdGluaW5lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdD1mcm9tKSkgCiAgCmRmCmBgYAoKYGBge3J9CiNzdHJpbmcgPC0gdW5pcXVlKGRmJGZyb20pIAojc3RyaW5nIDwtIHNldGRpZmYodW5pcXVlKGRmJGZyb20pLG5hbWVzKGNsaW5fbWFya2VyX2NvbHMpKQojY29sLmdyaWRfY2xpbiA8LSBzZXROYW1lcyhzYW1wbGUoYnJld2VyLnBhbChsZW5ndGgoc3RyaW5nKSxuYW1lPSJTZXQxIikpLHN0cmluZykKCnN0cmluZ19wcm90ZWlucyA8LSB1bmlxdWUoZGYkdG8pCmNvbC5ncmlkLnByb3QgPC0gc2V0TmFtZXMocmVwKCJncmV5ODAiLGxlbmd0aChzdHJpbmdfcHJvdGVpbnMpKSwgc3RyaW5nX3Byb3RlaW5zKQoKCgpjb2wuZ3JpZCA8LSBjKGNsaW5fbWFya2VyX2NvbHMsCiAgICAgICAgICAgICAgI2NvbC5ncmlkX2NsaW4sIAogICAgICAgICAgICAgIGNvbC5ncmlkLnByb3QpCgojIyBoaWdobGlnaHQKIyB0aHJlZS1jb2x1bW4gZGF0YSBmcmFtZSBpbiB3aGljaCB0aGUgZmlyc3QgdHdvIGNvbHVtbnMgY29ycmVzcG9uZCB0byByb3cgbmFtZXMgYW5kIGNvbHVtbiBuYW1lcyBpbiB0aGUgbWF0cml4LCBhbmQgdGhlIHRoaXJkIGNvbHVtbiBjb3JyZXNwb25kcyB0byB0aGUgZ3JhcGhpYyBwYXJhbWV0ZXJzCmJvcmRlcl9kZiA9IGRhdGEuZnJhbWUoYygiUGFyYXNpdGVtaWEiKSwgYygiQ0FMQ0EiKSwgYygxKSkKCgpwZGYocGFzdGUwKHJlc3VsdC50bXAuZGlyLCJjaG9yZERpYWdyYW0ucGRmIikpICN3aWR0aCA2LjkKCmNpcmNvcy5wYXIoZ2FwLmFmdGVyID0gYyhyZXAoMSwgbGVuZ3RoKHVuaXF1ZShkZltbMV1dKSktMSksIDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgxLCBsZW5ndGgodW5pcXVlKGRmW1syXV0pKS0xKSwgMTUpKQpjaG9yZERpYWdyYW0oZGYsCiAgICAgICAgICAgICMgIGJpZy5nYXAgPSAyNSwKICAgICAgICAgICAgIGdyaWQuY29sID0gY29sLmdyaWQsCiAgICAgICAgICAgICAjYW5ub3RhdGlvblRyYWNrID0gImdyaWQiLAogICAgICAgICAgICAgICAgICAgICAgICBiaWcuZ2FwID0gMTAsCiAgICAgICAgICAgIHNtYWxsLmdhcCA9IDEsCmxpbmsuYm9yZGVyID0gYm9yZGVyX2RmLAogICAgICAgICAgICAgYW5ub3RhdGlvblRyYWNrID0gTlVMTCwKICAgICAgICAgICAgIHByZUFsbG9jYXRlVHJhY2tzID0gbGlzdCh0cmFjay5oZWlnaHQgPSAuMSkpI21heChzdHJ3aWR0aCh1bmxpc3QoZGltbmFtZXMoZGYpKSkpKSkKY2lyY29zLnRyYWNrKHRyYWNrLmluZGV4ID0gMSwgcGFuZWwuZnVuID0gZnVuY3Rpb24oeCwgeSkgewogIGNpcmNvcy50ZXh0KENFTExfTUVUQSR4Y2VudGVyLCAKICAgICAgICAgICAgICBDRUxMX01FVEEkeWxpbVsxXSwKICAgICAgICAgICAgICBDRUxMX01FVEEkc2VjdG9yLmluZGV4LAogICAgICAgICAgICAgIGZhY2luZyA9ICJjbG9ja3dpc2UiLAogICAgICAgICAgICAgIGNleCA9IDAuNiwKICAgICAgICAgICAgICBuaWNlRmFjaW5nID0gVFJVRSwgCiAgICAgICAgICAgICAgYWRqID0gYygwLCAwLjkpKQp9LApiZy5ib3JkZXIgPSBOQSkKCiMKZGV2Lm9mZigpCmNpcmNvcy5jbGVhcigpCmBgYAoKIyBGaWd1cmUgNQoqKklkZW50aWZpY2F0aW9uIG9mIHNldmVyaXR5LWFzc29jaWF0ZWQgcGxhc21hIHByb3Rlb21pYyBwcm9maWxlcyoqCgpgYGB7cn0KIyMgV0dDTkEKIyMgaHR0cHM6Ly9iaW9pbmZvcm1hdGljc3dvcmtib29rLm9yZy90dXRvcmlhbHMvd2djbmEuaHRtbCNnc2MudGFiPTAKI2luc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikKI0Jpb2NNYW5hZ2VyOjppbnN0YWxsKCJXR0NOQSIpCgojIyBkYXRhIHdyYW5nbGluZwpzZWxlY3RlZC5hc3NheXMud2NuYSA8LSBkYXAucmVzICU+JSBmaWx0ZXIocC5hZGogPD0gMC4wMSkgJT4lIHB1bGwoQXNzYXkpCgojIyByZXF1aXJlczogcm93cyA9IHRyZWF0bWVudHMgYW5kIGNvbHVtbnMgPSBnZW5lIHByb2JlcwppbnB1dF9tYXQgPC0gZGF0YS53aWRlICU+JSAKICBpbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgZHBseXI6OnNlbGVjdChEQWlkLHN0dWR5X2lkLFRpbWUsIHNhbXBsZV9pZCksYnk9InNhbXBsZV9pZCIpICU+JSAKICBpbm5lcl9qb2luKHN1YmplY3RUYWJsZSAlPiUgZHBseXI6OnNlbGVjdChzdHVkeV9pZCksYnk9InN0dWR5X2lkIikgJT4lIAogIGZpbHRlcihUaW1lPT0iQWN1dGUiKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGVfaWQiKSAlPiUgCiAgIyMgcmVzdHJpY3RpbmcgdG8gcHJvdGVpbnMsIHNpZ25pZmljYW50IGFidW5kYW50IG92ZXIgY29udmFsZXNjZW5jZSAobTEyIHNhbXBsZXMpCiAgZHBseXI6OnNlbGVjdChzZWxlY3RlZC5hc3NheXMud2NuYSkgJT4lIAogIGFzLm1hdHJpeCgpICU+JQogIHNjYWxlKCkKCmlucHV0X21hdFsxOjUsMToxMF0KZGltKGlucHV0X21hdCkKYGBgCgogU2V0IHVwCgpgYGB7cn0KYWxsb3dXR0NOQVRocmVhZHMoKSAgICAgICAgICAjIGFsbG93IG11bHRpLXRocmVhZGluZyAob3B0aW9uYWwpCiM+IEFsbG93aW5nIG11bHRpLXRocmVhZGluZyB3aXRoIHVwIHRvIDQgdGhyZWFkcy4KCiMgQ2hvb3NlIGEgc2V0IG9mIHNvZnQtdGhyZXNob2xkaW5nIHBvd2Vycwpwb3dlcnMgPSBjKGMoMToxMCksIHNlcShmcm9tID0gMTIsIHRvID0gMjAsIGJ5ID0gMikpCgojIENhbGwgdGhlIG5ldHdvcmsgdG9wb2xvZ3kgYW5hbHlzaXMgZnVuY3Rpb24Kc2Z0ID0gcGlja1NvZnRUaHJlc2hvbGQoaW5wdXRfbWF0LCAgICAgICAgICAgICAjIDw9IElucHV0IGRhdGEKICAgICAgICAgICAgICAgICAgICAgICAgI2Jsb2NrU2l6ZSA9IDMwLAogICAgICAgICAgICAgICAgICAgICAgICBwb3dlclZlY3RvciA9IHBvd2VycywKICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IDUKKQojc2Z0JHBvd2VyRXN0aW1hdGUKCiMjIyMgU2NhbGUgaW5kZXBlbmRlbmNlICYgbWVhbiBjb25uZWN0aXZpdHkKCnNmdF90aWJibGUgPC0gYXNfdGliYmxlKHNmdCRmaXRJbmRpY2VzKQoKcGxvdC5zaSA8LSBzZnRfdGliYmxlICU+JSAKICBnZ3Bsb3QoYWVzKHg9UG93ZXIsCiAgICAgICAgICAgICB5PS1zaWduKHNsb3BlKSpTRlQuUi5zcSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGFiZWwoYWVzKGxhYmVsPVBvd2VyKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuOSwgY29sb3I9ImRhcmtyZWQiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlNjYWxlIGluZGVwZW5kZW5jZSIsCiAgICAgICB5PSJTY2FsZSBGcmVlIFRvcG9sb2d5IE1vZGVsIGZpdFxuIHNpZ25lZCBSXjIiLAogICAgICAgeD0gIlNvZnQgVGhyZXNob2xkIChwb3dlciIpCgpwbG90Lm1lYW5rIDwtIHNmdF90aWJibGUgJT4lIAogIGdncGxvdChhZXMoeD1Qb3dlciwKICAgICAgICAgICAgIHk9bWVhbi5rLikpICsKICAgIGdlb21fbGFiZWwoYWVzKGxhYmVsPVBvd2VyKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlPSJNZWFuIGNvbm5lY3Rpdml0eSIsCiAgICAgICB4PSJTb2Z0IFRocmVzaG9sZCAocG93ZXIpIiwKICAgICAgIHk9Ik1lYW4gQ29ubmVjdGl2aXR5IikKCnBsb3Quc2kgKyBwbG90Lm1lYW5rCmBgYAoKCmBgYHtyfQojI0J1aWxkIGNvLWV4cHJlc3Npb24gbmV0d29yawoKcGlja2VkX3Bvd2VyID0gNiNzZnQkcG93ZXJFc3RpbWF0ZSM2CnRlbXBfY29yIDwtIGNvciAgICAgICAKY29yIDwtIFdHQ05BOjpjb3IgICAgICAgICAjIEZvcmNlIGl0IHRvIHVzZSBXR0NOQSBjb3IgZnVuY3Rpb24gKGZpeCBhIG5hbWVzcGFjZSBjb25mbGljdCBpc3N1ZSkKbmV0d2sgPC0gYmxvY2t3aXNlTW9kdWxlcyhpbnB1dF9tYXQsICAjIDw9IGlucHV0IGhlcmUKICAgICAgICAgICAgICAgICAgICAgICAgICAjID09IEFkamFjZW5jeSBGdW5jdGlvbiA9PQogICAgICAgICAgICAgICAgICAgICAgICAgIHBvd2VyID0gcGlja2VkX3Bvd2VyLCAgIyA8PSBwb3dlciBoZXJlCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmV0d29ya1R5cGUgPSAic2lnbmVkIiwjInNpZ25lZCBoeWJyaWQiLCMic2lnbmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAjID09IFRyZWUgYW5kIEJsb2NrIE9wdGlvbnMgPT0KICAgICAgICAgICAgICAgICAgICAgICAgICBkZWVwU3BsaXQgPSA0LCAjc2Vuc2l0aXZlIG1vZHVsZSBkZXRlY3Rpb24gc2hvdWxkIGJlIHRvIG1vZHVsZSBzcGxpdHRpbmcsIDAgbGVhc3QgYW5kIDQgbW9zdCBzZW5zaXRpdmUKICAgICAgICAgICAgICAgICAgICAgICAgICBwYW1SZXNwZWN0c0RlbmRybyA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyBkZXRlY3RDdXRIZWlnaHQgPSAwLjc1LAogICAgICAgICAgICAgICAgICAgICAgICAgIG1pbk1vZHVsZVNpemUgPSAzMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4QmxvY2tTaXplID1uY29sKGlucHV0X21hdCksIzQwMDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICMgPT0gTW9kdWxlIEFkanVzdG1lbnRzID09CiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVhc3NpZ25UaHJlc2hvbGQgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlQ3V0SGVpZ2h0ID0gMC4yNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAjID09IFRPTSA9PSBBcmNoaXZlIHRoZSBydW4gcmVzdWx0cyBpbiBUT00gZmlsZSAoc2F2ZXMgdGltZSkKICAgICAgICAgICAgICAgICAgICAgICAgICBzYXZlVE9NcyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2F2ZVRPTUZpbGVCYXNlID0gIkVSIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAjID09IE91dHB1dCBPcHRpb25zCiAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtZXJpY0xhYmVscyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IDMpCgpjb3IgPC0gdGVtcF9jb3IgICAgICMgUmV0dXJuIGNvciBmdW5jdGlvbiB0byBvcmlnaW5hbCBuYW1lc3BhY2UKYGBgCgoKYGBge3IgY2x1c3Rlci1kZW5kcm99CiMjIyMjIENsdXN0ZXIgRGVuZHJvZ3JhbQojIENvbnZlcnQgbGFiZWxzIHRvIGNvbG9ycyBmb3IgcGxvdHRpbmcKbWVyZ2VkQ29sb3JzID0gbGFiZWxzMmNvbG9ycyhuZXR3ayRjb2xvcnMpCiMgUGxvdCB0aGUgZGVuZHJvZ3JhbSBhbmQgdGhlIG1vZHVsZSBjb2xvcnMgdW5kZXJuZWF0aAooY2x1c3Rlcl9kZW5kcm8gPC0gcGxvdERlbmRyb0FuZENvbG9ycygKICBuZXR3ayRkZW5kcm9ncmFtc1tbMV1dLAogIG1lcmdlZENvbG9yc1tuZXR3ayRibG9ja0dlbmVzW1sxXV1dLAogICJNb2R1bGUgY29sb3JzIiwKICBkZW5kcm9MYWJlbHMgPSBGQUxTRSwKICBoYW5nID0gMC4wMywKICBhZGRHdWlkZSA9IFRSVUUsCiAgZ3VpZGVIYW5nID0gMC4wNSApKQoKbW9kdWxlX2RmIDwtIGRhdGEuZnJhbWUoCiAgYXNzYXlfaWQgPSBuYW1lcyhuZXR3ayRjb2xvcnMpLAogIEFzc2F5ID0gZ3N1YigiXFxfLioiLCIiLG5hbWVzKG5ldHdrJGNvbG9ycykpLAogIGNvbG9ycyA9IGxhYmVsczJjb2xvcnMobmV0d2skY29sb3JzKQopCgptb2R1bGVfZGZbMTo1LF0KCnRtcCA8LSB1bmlxdWUobW9kdWxlX2RmJGNvbG9ycykKbW9kdWxlLmNvbHMgPC0gc2V0TmFtZXModG1wLCB0bXApCmBgYAoKCiMjIFN1cHBsZW1lbnRhcnkgRmlndXJlIDkKIyMjIEZpZ3VyZSBTOUEKYGBge3IgbnctbW9kdWxlLXNpemV9CiMjIGhvdyBtYW55IHByb3RlaXMgaW4gZWFjaCBtb2R1bGUKKG1vZHVsZV9vdmVydmlldyA8LSBtb2R1bGVfZGYgJT4lIAogIGdyb3VwX2J5KGNvbG9ycykgJT4lIAogIGNvdW50KCkgJT4lIAogIAogIGdncGxvdChhZXMoeCA9IGZjdF9yZW9yZGVyKGNvbG9ycywtbiksIHkgPSBuLCBmaWxsID0gY29sb3JzLCBsYWJlbCA9IG4pKSArCiAgICAgICAgIGdlb21fYmFyKHN0YXQgPSAic3VtbWFyeSIsIHBvc2l0aW9uID0gImRvZGdlIiwgc2hvdy5sZWdlbmQgPSBGKSArCiAgZ2VvbV90ZXh0KHN0YXQgPSAic3VtIiwgdmp1c3QgPSAtMC41LHNob3cubGVnZW5kID0gRiwgc2l6ZT0yKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCNsaW1pdHM9YygwLDMwMCksCiAgICAgICAgICAgICAgICAgICAgIGV4cGFuZCA9IGMoMCwgMjApKSArCiAgIHNjYWxlX3hfZGlzY3JldGUoZXhwYW5kID0gYygwLC0xKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1tb2R1bGUuY29scykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpCiAgICApICsgCiAgbGFicyh0aXRsZSA9ICJXR0NOQSBhbmFseXNpcyAtIHByb3RlaW4gbmV0d29yayBtb2R1bGVzIiwKICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJiYXNlZCBvbiAiLGRpbShpbnB1dF9tYXQpWzJdLCIgcHJvdGVpbnMgKGRpZmZlcmVudGlhbCBhYnVuZGFudCBwcm90ZWlucylcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAicHJvZmlsZWQgaW4gIixkaW0oaW5wdXRfbWF0KVsxXSwiIGFjdXRlIG1hbGFyaWEgc2FtcGxlcyIpLAogICAgICAgeD0iV0dDTkEgcHJvdGVpbiBtb2R1bGVzIiwKICAgICAgIHk9Im4gUHJvdGVpbnMiKSAKKQogIApgYGAKCgpgYGB7cn0KIyMjIyBnZW5lcmF0ZSBhbmQgZXhwb3J0IG5ldHdvcmtzIGZvciBhbGwgbW9kdWxlcwoKYXNzYXlzX29mX2ludGVyZXN0ID0gbW9kdWxlX2RmICMlPiUKICAjc3Vic2V0KGNvbG9ycyAlaW4lIGMoInR1cnF1b2lzZSIpKQoKbnB4X29mX2ludGVyZXN0ID0gaW5wdXRfbWF0Wyxhc3NheXNfb2ZfaW50ZXJlc3QkYXNzYXlfaWRdCm5weF9vZl9pbnRlcmVzdFsxOjUsMTo1XQojIyBjb2x1bW5zOiBBc3NheXMKIyMgcm93czogc2FtcGxlX2lkCgpUT00gPSBUT01zaW1pbGFyaXR5RnJvbUV4cHIobnB4X29mX2ludGVyZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcG93ZXIgPSBwaWNrZWRfcG93ZXIpCgojIEFkZCBnZW5lIG5hbWVzIHRvIHJvdyBhbmQgY29sdW1ucwpyb3cubmFtZXMoVE9NKSA9IGNvbG5hbWVzKG5weF9vZl9pbnRlcmVzdCkKY29sbmFtZXMoVE9NKSA9IGNvbG5hbWVzKG5weF9vZl9pbnRlcmVzdCkKCmVkZ2VfbGlzdCA9IGRhdGEuZnJhbWUoVE9NKSAlPiUKICByb3duYW1lc190b19jb2x1bW4oIkFzc2F5MSIpICU+JSAKICBwaXZvdF9sb25nZXIoY29scz0tQXNzYXkxLG5hbWVzX3RvID0gIkFzc2F5MiIsdmFsdWVzX3RvID0gImFkamFjZW5jeSIpICU+JSAKICBkaXN0aW5jdCgpICU+JQogICAgZmlsdGVyKEFzc2F5MSE9QXNzYXkyKSAlPiUgCiAgcmlnaHRfam9pbihtb2R1bGVfZGYgJT4lIHRyYW5zbXV0ZShtb2R1bGUxID0gY29sb3JzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXNzYXkxID0gQXNzYXkpKSAlPiUgCiAgcmlnaHRfam9pbihtb2R1bGVfZGYgJT4lIHRyYW5zbXV0ZShtb2R1bGUyID0gY29sb3JzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXNzYXkyID0gQXNzYXkpKSAlPiUgCiAgbmEub21pdCgpCgpgYGAKCiMjIEZpZ3VyZSA1QQoKYGBge3J9CiMjSGVhdG1hcCAtIHByb3RlaW4gYWRqYWNlbmN5CgptYXQgPC0gY29yKG5weF9vZl9pbnRlcmVzdCwgbWV0aG9kID0gInBlYXJzb24iKQpyb3cuYW5uby5kZiA8LSBkYXRhLmZyYW1lKGFzc2F5X2lkID0gcm93bmFtZXMobWF0KSkgJT4lIGxlZnRfam9pbihtb2R1bGVfZGYpICU+JSBkcGx5cjo6cmVuYW1lKE1vZHVsZSA9IGNvbG9ycykgCgooYXNzYXlfYWRqX2htIDwtIG1hdCAlPiUgCiAgSGVhdG1hcChuYW1lPSJwcm90ZWluLXByb3RlaW4gY29ycmVsYXRpb24gciIsCiAgICAgICAgICByaWdodF9hbm5vdGF0aW9uID0gSGVhdG1hcEFubm90YXRpb24oZGYgPSByb3cuYW5uby5kZiAlPiUgdHJhbnNtdXRlKE1vZHVsZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChNb2R1bGUgPSBtb2R1bGUuY29scyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gInJvdyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcGxlX2Fubm9fc2l6ZSA9IHVuaXQoMSwgIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19hbm5vdGF0aW9uX25hbWUgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9yb3QgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9zaWRlID0gInRvcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19sZWdlbmQgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kX3BhcmFtID0gbGlzdCh0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSkpLAogICAgICAgICAgcm93X3NwbGl0ID0gcm93LmFubm8uZGYkTW9kdWxlLAogICAgICAgICAgY29sdW1uX3NwbGl0ID0gcm93LmFubm8uZGYkTW9kdWxlLAogICAgICAgICAgcm93X2dhcCA9IHVuaXQoMCwgIm1tIiksCiAgICAgICAgICBjb2x1bW5fZ2FwID0gdW5pdCgwLCAibW0iKSwgCiAgICAgICAgICByb3dfZGVuZF93aWR0aCA9IHVuaXQoMywgIm1tIiksCiAgICAgICAgICByb3dfZGVuZF9ncCA9IGdwYXIobHdkPS4xKSwKICAgICAgICAgIGNvbHVtbl9kZW5kX2dwID0gZ3Bhcihsd2Q9LjEpLAogICAgICAgICAgY29sdW1uX2RlbmRfaGVpZ2h0ID0gdW5pdCgzLCAibW0iKSwgCiAgICAgICAgICBib3JkZXIgPSBUUlVFLAogICAgICAgICAgYm9yZGVyX2dwID0gZ3Bhcihsd2Q9LjEpLAogICAgICAgICAgY29sdW1uX3RpdGxlID0gTlVMTCwKICAgICAgICAgIHJvd190aXRsZSA9IE5VTEwsCiAgICAgICAgICBzaG93X3Jvd19uYW1lcyA9IEYsCiAgICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IEYsCiAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfd2lkdGggPSB1bml0KDIsICJjbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfaGVpZ2h0ID0gdW5pdCguMiwgImNtIikpCiAgICAgICAgICApKQpgYGAKCmBgYHtyfQojIEdldCBNb2R1bGUgRWlnZW5nZW5lcyBwZXIgY2x1c3RlcgpNRXMwIDwtIG1vZHVsZUVpZ2VuZ2VuZXMoaW5wdXRfbWF0LCBtZXJnZWRDb2xvcnMpJGVpZ2VuZ2VuZXMKCiMgUmVvcmRlciBtb2R1bGVzIHNvIHNpbWlsYXIgbW9kdWxlcyBhcmUgbmV4dCB0byBlYWNoIG90aGVyCk1FczAgPC0gb3JkZXJNRXMoTUVzMCkKbW9kdWxlX29yZGVyID0gbmFtZXMoTUVzMCkgJT4lIGdzdWIoIk1FIiwiIiwgLikKCiMgQWRkIHRyZWF0bWVudCBuYW1lcwojTUVzMCREQWlkIDwtIHJvdy5uYW1lcyhNRXMwKQoKIyB0aWR5IGRhdGEKbU1FIDwtIE1FczAgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGVfaWQiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gIm1vZHVsZSIsIHZhbHVlc190byA9ICJtb2R1bGVfZWlnZW5nZW5lcyIgLGNvbHMgPSAtc2FtcGxlX2lkKSAlPiUKICAgICAgc2VwYXJhdGUoc2FtcGxlX2lkLCAiXFx8IiwgaW50byA9IGMoInN0dWR5X2lkIiwiVGltZSIpLHJlbW92ZSA9IEYpICU+JSAKICBtdXRhdGUobW9kdWxlID0gZ3N1YigiTUUiLCAiIiwgbW9kdWxlKSwKICAgICAgICAgbW9kdWxlID0gZmFjdG9yKG1vZHVsZSwgbGV2ZWxzID0gbW9kdWxlX29yZGVyKSkgJT4lIAogIGlubmVyX2pvaW4oc3ViamVjdFRhYmxlLCAKICAgICAgICAgICAgIGJ5PSJzdHVkeV9pZCIpIApgYGAKCiMjIEZpZ3VyZSA1QgpgYGB7cn0KIyMgTW9kdWxlLXRyYWl0IHJlbGF0aW9uc2hpcAoKY29ycl9tb2R1bGVfZWlnZW5nZW5lX21ldGFfcmVzIDwtIG1NRSAlPiUgCiAgZHBseXI6OnNlbGVjdChtb2R1bGUsIG1vZHVsZV9laWdlbmdlbmVzLGNvbnRhaW5zKCJTT0ZBIikpICU+JSAKICBncm91cF9ieShtb2R1bGUpICU+JSAKICBjb3JyZWxhdGlvbihwX2FkanVzdCA9ICJmZHIiKSAKCmRmIDwtIHRpYmJsZShjb3JyX21vZHVsZV9laWdlbmdlbmVfbWV0YV9yZXMpICU+JSAKICBmaWx0ZXIoUGFyYW1ldGVyMT09Im1vZHVsZV9laWdlbmdlbmVzIikgJT4lIAogICAgbXV0YXRlKHI0ZmlsbCA9IGNhc2Vfd2hlbihwPjAuMDUgfiAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdD1yKSkgIAoobW9kdWxlX3RyYWl0X3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBkZiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9UGFyYW1ldGVyMiwgeT1Hcm91cCwgZmlsbD1yNGZpbGwsbGFibGU9cikpICsKICAgIGdlb21fdGlsZSgpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAociAlPiUgcm91bmQoMikpLAogICAgICAgICAgICAgICAgICBjb2xvciA9IGlmZWxzZShyNGZpbGw9PTAsICJncmV5MjAiLCAiYmxhY2siKSksCiAgICAgICAgICAgICAgc2l6ZT0xKSArCiAgICBzY2FsZV9jb2xvdXJfaWRlbnRpdHkoKSArCiAgICB0aGVtZV9idygpICsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKAogICAgICBsb3cgPSAiYmx1ZSIsCiAgICAgIGhpZ2ggPSAicmVkIiwKICAgICAgbWlkID0gIndoaXRlIiwKICAgICAgbWlkcG9pbnQgPSAwLAogICAgICBsaW1pdCA9IGMoLTEsMSkpICsKICAgIGxhYnModGl0bGUgPSAiTW9kdWxlLXRyYWl0IFJlbGF0aW9uc2hpcHMiLAogICAgICAgICB5PSJXR0NOQSBtb2R1bGVzIiwKICAgICAgICAgeCA9IE5VTEwsIAogICAgICAgICBmaWxsPSJyaG8iKSArCiAgICB0aGVtZSgjYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3I9IHJldihjKCJ5ZWxsb3ciLCJ0dXJxdW9pc2UiLCJyZWQiLCJncmV5IiwiZ3JlZW4iLCJicm93biIsImJsdWUiKSkpLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvcj0gcmV2KGMoInllbGxvdyIsInR1cnF1b2lzZSIsInJlZCIsImdyZXkiLCJncmVlbiIsImJyb3duIiwiYmx1ZSIpKSksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpKQpgYGAKCgpgYGB7cn0KIyMjIyBNb2R1bGUgbWVtYmVyc2hpcAoKIyMjICBHZXQgTW9kdWxlIEVpZ2VuZ2VuZXMgcGVyIGNsdXN0ZXIKTUVzIDwtIG1vZHVsZUVpZ2VuZ2VuZXMoaW5wdXRfbWF0LCBtZXJnZWRDb2xvcnMpJGVpZ2VuZ2VuZXMKCiMjIGNhbGN1bGF0ZSBNb2R1bGUgbWVtYmVyc2hpcApnZW5lTW9kdWxlTWVtYmVyc2hpcCA8LSBhcy5kYXRhLmZyYW1lKGNvcihpbnB1dF9tYXQsIE1FcywgdXNlID0gInAiKSkgCgpnZW5lTW9kdWxlTWVtYmVyc2hpcC50aWR5IDwtIGdlbmVNb2R1bGVNZW1iZXJzaGlwICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigiQXNzYXkiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtQXNzYXkpICU+JSAKICB0cmFuc211dGUoQXNzYXksCiAgICAgICAgICAgIE1vZHVsZSA9IHN0cl9yZW1vdmUobmFtZSwgIk1FIiksCiAgICAgICAgICAgIGdNTSA9IHZhbHVlKQoKIyMgY2FsY3VsYXRlIHB2YWx1ZSBmb3IgZ2VuZU1vZHVsZU1lbWJlcnNoaXAKTU1QdmFsdWUudGlkeSA8LSBhcy5kYXRhLmZyYW1lKGNvclB2YWx1ZVN0dWRlbnQoYXMubWF0cml4KGdlbmVNb2R1bGVNZW1iZXJzaGlwKSwgbnJvdyhpbnB1dF9tYXQpKSkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCJBc3NheSIpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IC1Bc3NheSkgJT4lIAogIHRyYW5zbXV0ZShBc3NheSwKICAgICAgICAgICAgTW9kdWxlID0gc3RyX3JlbW92ZShuYW1lLCAiTUUiKSwKICAgICAgICAgICAgcHZhbHVlID0gdmFsdWUpIAoKZ01NLnRpZHkgPC0gZ2VuZU1vZHVsZU1lbWJlcnNoaXAudGlkeSAlPiUgcmlnaHRfam9pbihNTVB2YWx1ZS50aWR5LGJ5PWMoIkFzc2F5IiwiTW9kdWxlIikpIAoKbW9kdWxlX3NwZWNpZmljX01NIDwtIG1vZHVsZV9kZiAlPiUgCiAgdHJhbnNtdXRlKEFzc2F5LAogICAgICAgICAgICBNb2R1bGUgPSBjb2xvcnMpICU+JSAKICBpbm5lcl9qb2luKGdNTS50aWR5KQpgYGAKCiMjIFN1cHBsZW1lbnRhcnkgRmlndXIgUzhCCmBgYHtyfQoodHVycXVvaXNlX21vZHVsZV9yZXN0cmljdGlvbnNfZGVuc2l0eSA8LSBtb2R1bGVfc3BlY2lmaWNfTU0gJT4lIAogICBtdXRhdGUoIi1sb2cxMChwdmFsdWUpIiA9IC1sb2cxMChwdmFsdWUpKSAlPiUgCiAgIHBpdm90X2xvbmdlcihjb2xzID0gYyhnTU0sIi1sb2cxMChwdmFsdWUpIikpICU+JSAKICAgbXV0YXRlKG5hbWVfbGFiZWwgPSBjYXNlX3doZW4obmFtZT09ImdNTSJ+InRocmVzaG9sZCA+IDAuNiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU9PSItbG9nMTAocHZhbHVlKSJ+InRocmVzaG9sZCA8IDAuMDUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BKSwKICAgICAgICAgIG5hbWVfbGFiZWwgPSBmYWN0b3IobmFtZV9sYWJlbCksCiAgICAgICAgICBjdXRvZmYgPSBjYXNlX3doZW4obmFtZT09ImdNTSJ+IDAuNiwjMC43NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lPT0iLWxvZzEwKHB2YWx1ZSkifiAtbG9nMTAoMC4wNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSksCiAgICAgICAgICBjdXRvZmZfcG9zX3kgPSBjYXNlX3doZW4obmFtZT09ImdNTSJ+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT09Ii1sb2cxMChwdmFsdWUpIn4gMC4wNCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BKQogICApICU+JSAKICAgZ2dwbG90KGFlcyh4PXZhbHVlKSkgKwogICBnZW9tX2RlbnNpdHkoc2hvdy5sZWdlbmQgPSBGLGxpbmV3aWR0aD0uMixmaWxsPSJ0dXJxdW9pc2UiKSArCiAgIHRoZW1lX21pbmltYWwoKSArCiAgIGZhY2V0X3dyYXAofm5hbWUsIG5jb2wgPSAxLGxhYmVsbGVyID0gbGFiZWxsZXIobmFtZT1jKCJnTU0iID0gIk1vZHVsZSBtZW1iZXJzaGlwIiwgIi1sb2cxMChwdmFsdWUpIiA9ICItbG9nMTAocHZhbHVlKSIpKSxzY2FsZXMgPSAiZnJlZSIpICsKICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1jdXRvZmYpLGxpbmV0eXBlPSJkYXNoZWQiKSArCiAgIGdlb21fdGV4dChhZXMoeD1jdXRvZmYsCiAgICAgICAgICAgICAgICAgeT1jdXRvZmZfcG9zX3ksCiAgICAgICAgICAgICAgICAgbGFiZWw9bmFtZV9sYWJlbCksIAogICAgICAgICAgICAgc2l6ZT0xLAogICAgICAgICAgICAgY2hlY2tfb3ZlcmxhcCA9IFRSVUUpICsKICAgbGFicyh5PSJkZW5zaXR5IiwKICAgICAgICB4PSIiKSkKYGBgCgojIyBGaWd1cmUgNUMKCmBgYHtyfQpyZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UgPC0gbW9kdWxlX3NwZWNpZmljX01NICU+JSAKICBmaWx0ZXIoTW9kdWxlPT0idHVycXVvaXNlIiwKICAgICAgICAgZ01NID4gMC42LCMwLjc1LAogICAgICAgICBwdmFsdWUgPCAwLjA1CiAgICAgICAgICkgJT4lIAogIGFycmFuZ2UoLXB2YWx1ZSkgJT4lIAogIHB1bGwoQXNzYXkpIAoKbGVuZ3RoKHJlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZSkKCmRhdGEuZnJhbWUoQXNzYXkgPSByZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UpICU+JSAKICBsZWZ0X2pvaW4oZGFwLnJlcyAlPiUgCiAgICAgICAgICAgICAgdHJhbnNtdXRlKEFzc2F5LCBVbmlQcm90KSkgJT4lCiAgdHJhbnNtdXRlKFVuaVByb3QpICU+JSAKICB3cml0ZV90c3YocGFzdGUwKHJlc3VsdC50bXAuZGlyLCJyZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UudHN2IikpCiAgI2hlYWQoKQpgYGAKCmBgYHtyfQojI09ubGluZSByZWFjdG9tZQpyZWFjdG9tZV9yZXN1bHQ8LSByZWFkX2RlbGltKCIuLi9NYW51c2NyaXB0LzIwMjUwMjI2X3Jlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZV9SZWFjdG9tZU9SQV9SZXN1bHQudHh0IikgJT4lIGphbml0b3I6OmNsZWFuX25hbWVzKCkKCgoocmVhY3RvbWVfb3JhIDwtIHJlYWN0b21lX3Jlc3VsdCAlPiUgCiAgYXJyYW5nZShlbnRpdGllc19mZHIpICU+JSAKICBoZWFkKG49MTApICU+JSAKICAgIG11dGF0ZShmYWNldF9sYWIgPSAidHVycXVvaXNlIG1vZHVsZSIpICU+JSAKCiAgIGdncGxvdChhZXMoeD1mY3RfcmVvcmRlcihwYXRod2F5X25hbWUsLWxvZzEwKGVudGl0aWVzX2ZkcikpLCAKICAgICAgICAgICAgICB5PS1sb2cxMChlbnRpdGllc19mZHIpKSkgKwoKICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuMSkgKwogICAgZ2VvbV9wb2ludChhZXMoY29sb3I9LWxvZzEwKGVudGl0aWVzX2ZkcikpLAogICAgICAgICAgICAgICBzaXplPTIpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWw9bnVtYmVyX2VudGl0aWVzX2ZvdW5kKSwKICAgICAgICAgICAgICBzaXplPTIsIG51ZGdlX3kgPSAuMSwgY29sb3I9ImJsYWNrIikrCiAgICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9ImxvZzEwIikgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJfd3JhcCh4LCB3aWR0aCA9IDQ1KSkgKwogICAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYgKSwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgY29vcmRfZmxpcCgpICsKICAgIGZhY2V0X2dyaWQofmZhY2V0X2xhYikgKwogICAgZ3VpZGVzKHNpemUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZT1UUlVFKSwKICAgICAgICAgICApICsKICAgICBsYWJzKHRpdGxlID0gIlJlYWN0b21lIGRhdGFiYXNlIHY4NiIsCiAgICAgICBjb2xvcj0iLWxvZzEwXG4oRkRSKSIsCiAgICAgICB5PSItbG9nMTAoRkRSKSIsCiAgICAgICB4PU5VTEwpCikKYGBgCgojIyBGaWd1cmUgNUQKYGBge3J9CndyYXBwZXIgPC0gZnVuY3Rpb24oeCwgLi4uKSAKewogIHBhc3RlKHN0cndyYXAoeCwgLi4uKSwgY29sbGFwc2UgPSAiXG4iKQp9CgphID0gIkltbXVub3JlZ3VsYXRvcnkgaW50ZXJhY3Rpb25zIGJldHdlZW4gYSBMeW1waG9pZCBhbmQgYSBub24tTHltcGhvaWQgY2VsbCIKZGYgPC0gcmVhY3RvbWVfcmVzdWx0ICU+JSAKICBhcnJhbmdlKGVudGl0aWVzX2ZkcikgJT4lIAogIGhlYWQobj0xMCkgJT4lIAogIGZpbHRlcihwYXRod2F5X25hbWU9PWEpICU+JSAKICB0cmFuc211dGUocGF0aHdheV9uYW1lLCBzdWJtaXR0ZWRfZW50aXRpZXNfZm91bmQpICU+JSAKICBzZXBhcmF0ZV9yb3dzKHN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCwgc2VwPSI7XFxzKiIpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBkYXRhLmxvbmcgJT4lIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIHRyYW5zbXV0ZShBc3NheSxOUFgsVW5pUHJvdCxzYW1wbGVfaWQsc3R1ZHlfaWQsVGltZSkgJT4lIGZpbHRlcihUaW1lPT0iQWN1dGUiKSwKICAgIGJ5PWMoInN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCI9IlVuaVByb3QiKQogICkgJT4lIAogIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCxieT0ic3R1ZHlfaWQiKQoKKHJlYWN0b21lX29yYV9JSUJMTkwgPC0gZGYgJT4lICBncm91cF9ieShBc3NheSwgc2V2ZXJpdHlfbGFiKSAlPiUgCiAgICBzdW1tYXJpc2UoTlBYbWVhbiA9IG1lYW4oTlBYKSwKICAgICAgICAgICAgICBOUFhtZWRpYW4gPSBtZWRpYW4oTlBYKSwKICAgICAgICAgICAgICBOUFhzZCA9IHNkKE5QWCksCiAgICAgICAgICAgICAgTlBYbiA9IG4oKSwKICAgICAgICAgICAgICBOUFhzZSA9IE5QWHNkIC8gc3FydChOUFhuKQogICAgKSAlPiUgCiAgICBtdXRhdGUoTlBYY2k5NSA9IE5QWHNlICogcXQoLjk3NSwgTlBYbiAtIDEpKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9QXNzYXksIHk9TlBYbWVhbiwgZ3JvdXA9c2V2ZXJpdHlfbGFiLCBjb2xvcj1zZXZlcml0eV9sYWIpKSArCiAgICBnZW9tX3BvaW50KHNpemU9LjI1KSArCiAgICBnZW9tX3BvbHlnb24oZmlsbD1OQSwgc2hvdy5sZWdlbmQgPSBGLCBsd2Q9MC4yKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh4ID0gQXNzYXksCiAgICAgICAgICAgICAgICAgICAgICB5bWluPU5QWG1lYW4tTlBYY2k5NSwgCiAgICAgICAgICAgICAgICAgICAgICB5bWF4PU5QWG1lYW4rTlBYY2k5NSwgKSwKICAgICAgICAgICAgICAgICAgbGluZXdpZHRoPS41LCAKICAgICAgICAgICAgICAgICAgd2lkdGg9LjIsCiAgICAgICAgICAgICAgICAgIGFscGhhPS41KSArCiAgICAjIE1ha2UgaXQgY2lyY3VsYXIhCiAgICBjb29yZF9wb2xhcihjbGlwID0gIm9mZiIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHg9IiIsCiAgICAgICAgIHk9Im1lYW4gKE5QWCkgKy0gOTUlIENJIiwKCiAgICAgICAgIHRpdGxlID0gd3JhcHBlcihhLCB3aWR0aCA9IDQwKSwKICAgICAgICAgICAgICAgICAgY29sb3I9Im1lYW4gKE5QWCkgKy0gOTUlIENJIikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1wYXRpZW50X2tjbHVzdDNfbGFiKSArCiAgICAjIEFubm90YXRlIHRoZSBiYXJzIGFuZCB0aGUgbG9sbGlwb3BzIHNvIHRoZSByZWFkZXIgdW5kZXJzdGFuZHMgdGhlIHNjYWxpbmcKICAgIGFubm90YXRlKHggPSAwLCB5ID0gMCwgbGFiZWwgPSAiMCIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDEsIGxhYmVsID0gIjEiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogICAgYW5ub3RhdGUoeCA9IDAsIHkgPSAyLCBsYWJlbCA9ICIyIiwgZm9udGZhY2UgPTIsIGdlb20gPSAidGV4dCIsIGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSAxLjUpICsKICAgIGFubm90YXRlKHggPSAwLCB5ID0gMywgbGFiZWwgPSAiMyIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSA0KSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSwgZmFjZT0nYm9sZCcpLAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKICApCmBgYAoKYGBge3J9CmEgPSAiTmV1dHJvcGhpbCBkZWdyYW51bGF0aW9uIgpkZiA8LSByZWFjdG9tZV9yZXN1bHQgJT4lIAogIGFycmFuZ2UoZW50aXRpZXNfZmRyKSAlPiUgCiAgaGVhZChuPTEwKSAlPiUgCiAgZmlsdGVyKHBhdGh3YXlfbmFtZT09YSkgJT4lIAogIHRyYW5zbXV0ZShwYXRod2F5X25hbWUsIHN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCkgJT4lIAogIHNlcGFyYXRlX3Jvd3Moc3VibWl0dGVkX2VudGl0aWVzX2ZvdW5kLCBzZXA9IjtcXHMqIikgJT4lIAogIGxlZnRfam9pbigKICAgIGRhdGEubG9uZyAlPiUgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUsIGJ5PSJzYW1wbGVfaWQiKSAlPiUgdHJhbnNtdXRlKEFzc2F5LE5QWCxVbmlQcm90LHNhbXBsZV9pZCxzdHVkeV9pZCxUaW1lKSAlPiUgZmlsdGVyKFRpbWU9PSJBY3V0ZSIpLAogICAgYnk9Yygic3VibWl0dGVkX2VudGl0aWVzX2ZvdW5kIj0iVW5pUHJvdCIpCiAgKSAlPiUgCiAgaW5uZXJfam9pbihwYXRpZW50X2NsdXN0LGJ5PSJzdHVkeV9pZCIpCgoocmVhY3RvbWVfb3JhX05EIDwtIGRmICU+JSAgZ3JvdXBfYnkoQXNzYXksIHNldmVyaXR5X2xhYikgJT4lIAogICAgc3VtbWFyaXNlKE5QWG1lYW4gPSBtZWFuKE5QWCksCiAgICAgICAgICAgICAgTlBYbWVkaWFuID0gbWVkaWFuKE5QWCksCiAgICAgICAgICAgICAgTlBYc2QgPSBzZChOUFgpLAogICAgICAgICAgICAgIE5QWG4gPSBuKCksCiAgICAgICAgICAgICAgTlBYc2UgPSBOUFhzZCAvIHNxcnQoTlBYbikKICAgICkgJT4lIAogICAgbXV0YXRlKE5QWGNpOTUgPSBOUFhzZSAqIHF0KC45NzUsIE5QWG4gLSAxKSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PUFzc2F5LCB5PU5QWG1lYW4sIGdyb3VwPXNldmVyaXR5X2xhYiwgY29sb3I9c2V2ZXJpdHlfbGFiKSkgKwogICAgZ2VvbV9wb2ludChzaXplPS4yNSkgKwogICAgZ2VvbV9wb2x5Z29uKGZpbGw9TkEsIHNob3cubGVnZW5kID0gRiwgbHdkPTAuMikgKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeCA9IEFzc2F5LAogICAgICAgICAgICAgICAgICAgICAgeW1pbj1OUFhtZWFuLU5QWGNpOTUsIAogICAgICAgICAgICAgICAgICAgICAgeW1heD1OUFhtZWFuK05QWGNpOTUsICksCiAgICAgICAgICAgICAgICAgIGxpbmV3aWR0aD0uNSwgICAgCiAgICAgICAgICAgICAgICAgIHdpZHRoPS4yLAogICAgICAgICAgICAgICAgICBhbHBoYT0uNSkgKwogICAgIyBNYWtlIGl0IGNpcmN1bGFyIQogICAgY29vcmRfcG9sYXIoY2xpcCA9ICJvZmYiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh4PSIiLAogICAgICAgICB0aXRsZSA9IHdyYXBwZXIoYSwgd2lkdGggPSA0MCksCiAgICAgICAgICAgICAgICAgIGNvbG9yPSJtZWFuIChOUFgpICstIDk1JSBDSSIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9cGF0aWVudF9rY2x1c3QzX2xhYikgKwogICAgIyBBbm5vdGF0ZSB0aGUgYmFycyBhbmQgdGhlIGxvbGxpcG9wcyBzbyB0aGUgcmVhZGVyIHVuZGVyc3RhbmRzIHRoZSBzY2FsaW5nCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDAsIGxhYmVsID0gIjAiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogICAgYW5ub3RhdGUoeCA9IDAsIHkgPSAxLCBsYWJlbCA9ICIxIiwgZm9udGZhY2UgPTIsIGdlb20gPSAidGV4dCIsIGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSAxLjUpICsKICAgIGFubm90YXRlKHggPSAwLCB5ID0gMiwgbGFiZWwgPSAiMiIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDMsIGxhYmVsID0gIjMiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogICAgdGhlbWUoCiAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJncmF5MTIiLCBzaXplID0gNCksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTUsIGZhY2U9J2JvbGQnKSwKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCiAgKQpgYGAKCmBgYHtyfQphID0gIlRORlIyIG5vbi1jYW5vbmljYWwgTkYta0IgcGF0aHdheSIKZGYgPC0gcmVhY3RvbWVfcmVzdWx0ICU+JSAKICBhcnJhbmdlKGVudGl0aWVzX2ZkcikgJT4lIAogIGhlYWQobj0xMCkgJT4lIAogIGZpbHRlcihwYXRod2F5X25hbWU9PWEpICU+JSAKICB0cmFuc211dGUocGF0aHdheV9uYW1lLCBzdWJtaXR0ZWRfZW50aXRpZXNfZm91bmQpICU+JSAKICBzZXBhcmF0ZV9yb3dzKHN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCwgc2VwPSI7XFxzKiIpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBkYXRhLmxvbmcgJT4lIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIHRyYW5zbXV0ZShBc3NheSxOUFgsVW5pUHJvdCxzYW1wbGVfaWQsc3R1ZHlfaWQsVGltZSkgJT4lIGZpbHRlcihUaW1lPT0iQWN1dGUiKSwKICAgIGJ5PWMoInN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCI9IlVuaVByb3QiKQogICkgJT4lIAogIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCxieT0ic3R1ZHlfaWQiKQoKKHJlYWN0b21lX29yYV9UTkZSMiA8LSBkZiAlPiUgIGdyb3VwX2J5KEFzc2F5LCBzZXZlcml0eV9sYWIpICU+JSAKICAgIHN1bW1hcmlzZShOUFhtZWFuID0gbWVhbihOUFgpLAogICAgICAgICAgICAgIE5QWG1lZGlhbiA9IG1lZGlhbihOUFgpLAogICAgICAgICAgICAgIE5QWHNkID0gc2QoTlBYKSwKICAgICAgICAgICAgICBOUFhuID0gbigpLAogICAgICAgICAgICAgIE5QWHNlID0gTlBYc2QgLyBzcXJ0KE5QWG4pCiAgICApICU+JSAKICAgIG11dGF0ZShOUFhjaTk1ID0gTlBYc2UgKiBxdCguOTc1LCBOUFhuIC0gMSkpICU+JSAKICAgIGdncGxvdChhZXMoeD1Bc3NheSwgeT1OUFhtZWFuLCBncm91cD1zZXZlcml0eV9sYWIsIGNvbG9yPXNldmVyaXR5X2xhYikpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0uMjUpICsKICAgIGdlb21fcG9seWdvbihmaWxsPU5BLCBzaG93LmxlZ2VuZCA9IEYsIGx3ZD0wLjIpICsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHggPSBBc3NheSwKICAgICAgICAgICAgICAgICAgICAgIHltaW49TlBYbWVhbi1OUFhjaTk1LCAKICAgICAgICAgICAgICAgICAgICAgIHltYXg9TlBYbWVhbitOUFhjaTk1KSwKICAgICAgICAgICAgICAgICAgbGluZXdpZHRoPS41LAogICAgICAgICAgICAgICAgICB3aWR0aD0uMiwKICAgICAgICAgICAgICAgICAgYWxwaGE9LjUpICsKICAgICMgTWFrZSBpdCBjaXJjdWxhciEKICAgIGNvb3JkX3BvbGFyKGNsaXAgPSAib2ZmIikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnMoeD1OVUxMLAogICAgICAgICBjb2xvcj0ibWVhbiAoTlBYKSArLSA5NSUgQ0kiLAogICAgICAgICB0aXRsZSA9IHdyYXBwZXIoYSwgd2lkdGggPSA0MCkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9cGF0aWVudF9rY2x1c3QzX2xhYikgKwogICAgIyBBbm5vdGF0ZSB0aGUgYmFycyBhbmQgdGhlIGxvbGxpcG9wcyBzbyB0aGUgcmVhZGVyIHVuZGVyc3RhbmRzIHRoZSBzY2FsaW5nCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDAsIGxhYmVsID0gIjAiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogICAgYW5ub3RhdGUoeCA9IDAsIHkgPSAxLCBsYWJlbCA9ICIxIiwgZm9udGZhY2UgPTIsIGdlb20gPSAidGV4dCIsIGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSAxLjUpICsKICAgIGFubm90YXRlKHggPSAwLCB5ID0gMiwgbGFiZWwgPSAiMiIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDMsIGxhYmVsID0gIjMiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogIGFubm90YXRlKHggPSAwLCB5ID0gNCwgbGFiZWwgPSAiNCIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICB0aGVtZSgKICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSA0KSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSwgZmFjZT0nYm9sZCcpLAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKKQpgYGAKCgojIEZpZ3VyZSA2CioqU2V2ZXJpdHktYXNzb2NpYXRlZCBwcm9maWxlcyBvZiBjb25kZW5zZWQgMTEtIHByb3RlaW4gc2lnbmF0dXJlIGluIG1hbGFyaWEgYW5kIG90aGVyIGZlYnJpbGUgaW5mZWN0aW9ucy4qKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShtaXhPbWljcykKZGF0YS5tbyA8LSBkZl9hY3V0ZV9wYXRjbHVzdF9pbmNsX2NvbnYgJT4lIAogIGZpbHRlcihBc3NheSAlaW4lIHJlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBBc3NheSwgdmFsdWVzX2Zyb20gPSBOUFgsIGlkX2NvbHM9YyhzZXZlcml0eV9sYWIsc2FtcGxlX2lkKSkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic2FtcGxlX2lkIikKClggPC0gZGF0YS5tbyAlPiUgZHBseXI6OnNlbGVjdCgtYyhzZXZlcml0eV9sYWIpKQpZIDwtIGRhdGEubW8kc2V2ZXJpdHlfbGFiCiMjIyMjCmRhdGEucGNhIDwtIG1peE9taWNzOjpwY2EoWCwgbmNvbXA9MTAsIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gVFJVRSkKcGxvdChkYXRhLnBjYSkKcGxvdEluZGl2KGRhdGEucGNhLCAKICAgICAgICAgIGdyb3VwID0gWSwKICAgICAgICAgIGluZC5uYW1lcyA9IEYsCiAgICAgICAgICBsZWdlbmQgPSBUUlVFLCAKICAgICAgICAgIGNvbC5wZXIuZ3JvdXAgPSBwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYsCiAgICAgICAgICB0aXRsZSA9ICdQQ0Egb24gYWxsIE5QWCBkYXRhJykKIyMjIyMKIyMjIFBMUy1EaXNjcmltaW5hbnQgQW5hbHlzaXMgYmFzZWQgb24gc2V2ZXJpdHkgZ3JvdXBzCgpkYXRhLnBsc2RhIDwtIG1peE9taWNzOjpwbHNkYShYLCBZLCBuY29tcCA9IDEwKQojIHRha2VzIGEgY291cGxlIG9mIG1pbnV0ZXMgdG8gcnVuCnBlcmYuZGF0YS5wbHNkYSA8LSBwZXJmKGRhdGEucGxzZGEsIAogICAgICAgICAgICAgICAgICAgICAgICB2YWxpZGF0aW9uID0gIk1mb2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgZm9sZHMgPSA1LAogICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzc0JhciA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgIGF1YyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICBucmVwZWF0ID0gMTApICMxMDAKIyMjIyMjIyMjIyMjIyMjIwoocGxvdChwZXJmLmRhdGEucGxzZGEsIGNvbCA9IGNvbG9yLm1peG8oMTozKSwgc2QgPSBUUlVFLCBsZWdlbmQucG9zaXRpb24gPSAiaG9yaXpvbnRhbCIpKQoKIyMjIyMjCmxpc3Qua2VlcFggPC0gYygxOjEwKSAjIGdyaWQgb2YgcG9zc2libGUga2VlcFggdmFsdWVzIHRoYXQgd2lsbCBiZSB0ZXN0ZWQgZm9yIGVhY2ggY29tcG9uZW50CnR1bmUuc3Bsc2RhIDwtIHR1bmUuc3Bsc2RhKFgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBuY29tcCA9IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YWxpZGF0aW9uID0gIk1mb2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9sZHMgPSA1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3NCYXIgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzdCA9ICJjZW50cm9pZHMuZGlzdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUgPSAiQkVSIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC5rZWVwWCA9IGxpc3Qua2VlcFgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBucmVwZWF0ID0gMTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBjcHVzID0gOCkKIyMjIyMKIyMgVGhlIGNsYXNzaWZpY2F0aW9uIGVycm9yIHJhdGVzIGZvciBlYWNoIGNvbXBvbmVudCBjb25kaXRpb25hbCBvbiB0aGUgbGFzdCBjb21wb25lbnQgYXJlIHJlcHJlc2VudGVkIGJlbG93LCBmb3IgYWxsIGNvbXBvbmVudHMgc3BlY2lmaWVkIGluIHRoZSB0dW5lIGZ1bmN0aW9uLgpwbG90KHR1bmUuc3Bsc2RhKQplcnJvciA8LSB0dW5lLnNwbHNkYSRlcnJvci5yYXRlICAjIGVycm9yIHJhdGUgcGVyIGNvbXBvbmVudCBmb3IgdGhlIGtlZXBYIGdyaWQKbmNvbXAgPC0gdHVuZS5zcGxzZGEkY2hvaWNlLm5jb21wJG5jb21wCm5jb21wCm5jb21wID0gMgojIyMjIwpzZWxlY3Qua2VlcFggPC0gdHVuZS5zcGxzZGEkY2hvaWNlLmtlZXBYWzE6bmNvbXBdICAjIG9wdGltYWwgbnVtYmVyIG9mIHZhcmlhYmxlcyB0byBzZWxlY3QKc2VsZWN0LmtlZXBYCgojIyMjIwoKc3Bsc2RhLmRhdGEgPC0gbWl4T21pY3M6OnNwbHNkYShYLCBZLCBuY29tcCA9IG5jb21wLCBrZWVwWCA9IHNlbGVjdC5rZWVwWCkgCgojIyMjIwoKcGxvdEluZGl2KHNwbHNkYS5kYXRhLCAKICAgICAgICAgIGNvbXAgPSBjKDEsMiksCiAgICAgICAgICBncm91cCA9IFksIAogICAgICAgICAgaW5kLm5hbWVzID0gRiwgCiAgICAgICAgICBlbGxpcHNlID0gVFJVRSwKICAgICAgICAgICNjb2wucGVyLmdyb3VwID0gIHBhdGllbnRfa2NsdXN0M19sYWIsCiAgICAgICAgICBsZWdlbmQgPSBULCAKICAgICAgICAgIHRpdGxlID0gJ3NQTFMtREEgb24gZGF0YSwgY29tcCAxICYgMicpCgpwbG90TG9hZGluZ3Moc3Bsc2RhLmRhdGEsIGNvbXAgPSAxLG5kaXNwbGF5PTIwLCB0aXRsZSA9ICdMb2FkaW5ncyBvbiBjb21wIDEnLGxlZ2VuZC5jb2xvciA9ICBwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYsIAogICAgICAgICAgICAgY29udHJpYiA9ICdtYXgnLCBtZXRob2QgPSAnbWVhbicpCgpwbG90TG9hZGluZ3Moc3Bsc2RhLmRhdGEsIGNvbXAgPSAyLG5kaXNwbGF5ID0gMTAsIHRpdGxlID0gJ0xvYWRpbmdzIG9uIGNvbXAgMicsIGxlZ2VuZC5jb2xvciA9ICBwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYsIAogICAgICAgICAgICAgY29udHJpYiA9ICdtYXgnLCBtZXRob2QgPSAnbWVhbicpCgphdWMuc3Bsc2RhIDwtIGF1cm9jKHNwbHNkYS5kYXRhLCByb2MuY29tcCA9IDIsIHByaW50ID0gRkFMU0UpICMgQVVST0MgZm9yIHRoZSBmaXJzdCBjb21wb25lbnQKYXVjLnNwbHNkYSRncmFwaC5Db21wMQoKYXVyb2Moc3Bsc2RhLmRhdGEsIHJvYy5jb21wID0gMSwgcHJpbnQgPSBGQUxTRSkgCmBgYAoKIyMgRmlndXJlIDZBCmBgYHtyfQpzcGxzZGEua2NsdXN0LmNsdXN0ZXJzIDwtIHBsb3RJbmRpdihzcGxzZGEuZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXAgPSBjKDEsMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gWSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZC5uYW1lcyA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGxpcHNlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sLnBlci5ncm91cCA9IHBhdGllbnRfa2NsdXN0M19sYWJfY29udiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gJ3NQTFMtREEgb24gZGF0YSwgY29tcCAxICYgMicpCgooc3Bsc2RhLmtjbHVzdC5jbHVzdGVycy5nZ3Bsb3QgPC0gc3Bsc2RhLmtjbHVzdC5jbHVzdGVycyRkZiAlPiUgCiAgICBtdXRhdGUoZ3JvdXAgPSBmYWN0b3IoZ3JvdXAsIGxldmVscz1jKCJzZXZlcmUiLCJtb2RlcmF0ZSIsIm1pbGQiLCJjb252YWxlc2NlbmNlIikpKSAlPiUgIAogICAgCiAgICBnZ3Bsb3QoYWVzKHg9eCx5PXksY29sb3I9Z3JvdXApKSArCiAgICBnZ2ZvcmNlOjpnZW9tX21hcmtfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoZ3JvdXApLCBmaWxsPWdyb3VwKSxhbHBoYT0uMSxzaG93LmxlZ2VuZCA9IEYsIGV4cGFuZCA9IHVuaXQoMC41LCJtbSIpKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC41KSArIAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1wYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYpICsKICAgIAogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnModGl0bGUgPSAic3BhcnNlIFBMUy1EQSIsCiAgICAgICAgIGNvbG9yPSBOVUxMLAogICAgICAgICB4PXBhc3RlMCgiWC12YXJpYXRlIDE6ICIscm91bmQoc3Bsc2RhLmRhdGEkcHJvcF9leHBsX3ZhciRYW1sxXV0qMTAwLDEpLCIlIGV4cGwuIHZhciIpLAogICAgICAgICB5PXBhc3RlMCgiWC12YXJpYXRlIDI6ICIscm91bmQoc3Bsc2RhLmRhdGEkcHJvcF9leHBsX3ZhciRYW1syXV0qMTAwLDEpLCIlIGV4cGwuIHZhciIpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSAKKQoKYGBgCgojIyBGaWd1cmUgNkIKYGBge3J9CnBsc2RhX2xvYWRpbmdzLmRmIDwtICAgCiAgZGF0YS5mcmFtZShzcGxzZGEuZGF0YSRsb2FkaW5ncyRYKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJBc3NheSIpICU+JSAKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAiY29tcCIsdmFsdWVzX3RvID0gInZhbHVlcyIsY29scyA9IC1Bc3NheSkgJT4lIAogIGZpbHRlcih2YWx1ZXMgIT0gMCwKICAgICAgICAgY29tcCAlaW4lIGMoImNvbXAxIiwiY29tcDIiKSkgJT4lIAogIGdyb3VwX2J5KGNvbXApICU+JSAKICBtdXRhdGUodmFsdWVzID0gc2NhbGVzOjpyZXNjYWxlKHZhbHVlcywgdG89YygtMSwxKSkpICU+JSAKICB1bmdyb3VwKCkgCgoocGxzZGFfbG9hZGluZ3Mudm9sY2Fuby5hbHQgPC0gIHBsc2RhX2xvYWRpbmdzLmRmICU+JSAKICAgIGdncGxvdChhZXMoeD1mY3RfcmVvcmRlcihBc3NheSx2YWx1ZXMsLmRlc2MgPSBUKSwgeT12YWx1ZXMsIGNvbG9yPWNvbXAsZmlsbD1jb21wKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTAuNSxhbHBoYT0xKSArCiAgICBnZW9tX2NvbCh3aWR0aCA9IDAuMDEpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKGNvbXAxID0gIiMxZjc4YjQiLGNvbXAyID0gIiNiMmRmOGEiKSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoY29tcDEgPSAiIzFmNzhiNCIsY29tcDIgPSAiI2IyZGY4YSIpKSArCiAgICBsYWJzKHg9IiIsCiAgICAgICAgIGZpbGw9TlVMTCwKICAgICAgICAgY29sb3I9TlVMTCwKICAgICAgICAgeT0ic2NhbGVkIGxvYWRpbmcgdmFsdWVzIiwKICAgICAgICAgdGl0bGU9InNQTFNEQSBsb2FkaW5ncyIpICsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbj0icmlnaHQiLCAKICAgICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMCwgInB0IikpKQpgYGAKCmBgYHtyfQptYWxhcmlhLnNldmVyaXR5LnNpZ2FudHVyZSA8LSBkYXRhLmZyYW1lKHNwbHNkYS5kYXRhJGxvYWRpbmdzJFgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oIkFzc2F5IikgJT4lIAogIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJjb21wIix2YWx1ZXNfdG8gPSAidmFsdWVzIixjb2xzID0gLUFzc2F5KSAlPiUgCiAgZmlsdGVyKHZhbHVlcyAhPSAwLAogICAgICAgICBjb21wICVpbiUgYygiY29tcDEiKSMsImNvbXAyIikKICAgICAgICAgKQpgYGAKCiMjIEZpZ3VyZSA2QwpgYGB7cn0KbXlfY29tcGFyaXNvbnNfc2V2ZXJlX2NvbnYgPC0gbGlzdChjKCJzZXZlcmUiLCAibW9kZXJhdGUiKSwgYygibW9kZXJhdGUiLCAibWlsZCIpLCBjKCJzZXZlcmUiLCAibWlsZCIpLGMoIm1pbGQiLCJjb252YWxlc2NlbmNlIikpCgpzcGxzZGEuYzEudG9wOSA8LSBwbHNkYV9sb2FkaW5ncy5kZiAlPiUgCiAgZmlsdGVyKGNvbXA9PSJjb21wMSIpICU+JSAKICBzbGljZV9taW4obj05LCBvcmRlcl9ieSA9IHZhbHVlcykgJT4lIHB1bGwoQXNzYXkpIyAlPiUgCgooc3Bsc2RhLmMxLnRvcDkgPC0gZGZfYWN1dGVfcGF0Y2x1c3RfaW5jbF9jb252ICU+JSAKCiAgICBkcGx5cjo6ZmlsdGVyKEFzc2F5ICVpbiUgYyhzcGxzZGEuYzEudG9wOSkpICU+JSAKICAgIG11dGF0ZShBc3NheSA9IGZhY3RvcihBc3NheSwgbGV2ZWxzID0gYyhzcGxzZGEuYzEudG9wOSkpKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9c2V2ZXJpdHlfbGFiLCB5PU5QWCwgY29sb3I9c2V2ZXJpdHlfbGFiLCBmaWxsPXNldmVyaXR5X2xhYikpICsgCiAgICBnZW9tX3Zpb2xpbih0cmltID0gRixhbHBoYT0uOSkgKwogICAgZ2VvbV9qaXR0ZXIoc2l6ZT0wLjI1LHNob3cubGVnZW5kID0gRiwgd2lkdGggPSAwLjA1LCBhbHBoYT0xLCBjb2xvcj0iZ3JleTIwIikgKwogICAgZ2VvbV9ib3hwbG90KGFscGhhPS43LHdpZHRoPTAuMjUsb3V0bGllci5zaGFwZSA9IE5BLGNvbG9yPSJibGFjayIsIGZhdHRlbiA9IDIsbHdkPS4yNSxzaG93LmxlZ2VuZCA9IEYpICsKICAgIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAid2lsY294LnRlc3QiLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnNlcCA9ICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgaGlkZS5ucyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5zaWduaWYiICwKICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IC41LAogICAgICAgICAgICAgICAgICAgICAgIHNpemU9MiwKICAgICAgICAgICAgICAgICAgICAgICBsd2QgPSAuMiwKICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9bXlfY29tcGFyaXNvbnNfc2V2ZXJlX2NvbnYsCiAgICAgICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgICBmYWNldF93cmFwKH5Bc3NheSxuY29sID0gMyxzY2FsZXMgPSAiZnJlZV95IikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHg9IiIsCiAgICAgICAgIGNvbG9yPU5VTEwsCiAgICAgICAgIGZpbGw9TlVMTCkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gcGF0aWVudF9rY2x1c3QzX2xhYl9jb252KSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IHBhdGllbnRfa2NsdXN0M19sYWJfY29udikpCmBgYAoKYGBge3J9CiMjI3Bsc2RhLnNlbGVjdGlvbiA8LSBkYXRhLmZyYW1lKHNwbHNkYS5kYXRhJGxvYWRpbmdzJFgpICU+JSAKIyAgcm93bmFtZXNfdG9fY29sdW1uKCJBc3NheSIpICU+JSAKIyAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImNvbXAiLHZhbHVlc190byA9ICJ2YWx1ZXMiLGNvbHMgPSAtQXNzYXkpICU+JSAKIyAgZmlsdGVyKHZhbHVlcyAhPSAwLAojICAgICAgICAgY29tcCAlaW4lIGMoImNvbXAxIiwiY29tcDIiKSkgJT4lIAojICBwdWxsKEFzc2F5KQpwbHNkYS5zZWxlY3Rpb24gPC0gbWFsYXJpYS5zZXZlcml0eS5zaWdhbnR1cmUgJT4lIHB1bGwoQXNzYXkpCgpkYXRhLmZyYW1lKEFzc2F5ID0gcGxzZGEuc2VsZWN0aW9uKSAlPiUgCiAgbGVmdF9qb2luKHVuaXZlcnNlLnByb3RlaW5zLGJ5PSJBc3NheSIpICU+JSAKICB0cmFuc211dGUoQXNzYXksIFVuaVByb3QpIyAlPiUgCiAgI3dyaXRlX3RzdihwYXN0ZTAocmVzdWx0LmRpciwiTUlQX1NldmVyaXR5X1Byb3RlaW5fc2lnbmF0dXJlX3VuaXByb3RpZC50c3YiKSkKYGBgCgojIyBGaWd1cmUgNkQKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgRXhwbG9yZSAxNTM2IGRhdGEgc2V0IC0gTUdIIENvdmlkLTE5IHN0dWR5LCBGaWxiaW4gZXQgYWwuIDIwMjEKCiMjIyMgTWFrZSBkYXRhIHJlYWR5CgojIGlkZW50aWZ5IHByb3RlaW5zIHdpdGggTlBYIGJlbG93IExPRCBpbiBtb3JlIHRoYW4gNzAlIG9mIHNhbXBsZXMKYXNzYXlzMnJtIDwtIGNvdmlkX05QWGRhdGEgJT4lIAogIG11dGF0ZShiZWxvd0xPRCA9IExPRD5OUFgpICU+JSAKICBncm91cF9ieShBc3NheSkgJT4lIAogIGNvdW50KGJlbG93TE9ELHNvcnQ9VFJVRSkgJT4lIAogIGZpbHRlcihiZWxvd0xPRD09VCwKICAgICAgICAgbiA+IGxlbmd0aCh1bmlxdWUoY292aWRfTlBYZGF0YSRTYW1wbGVJRCkpKjAuNykgJT4lIAogIHB1bGwoQXNzYXkpCgojIHJlbW92ZSBwcm90ZWlucyBpZGVudGlmaWVkIGFib3ZlIGZyb20gZGF0YQpjb3ZpZF9OUFhkYXRhX3JtIDwtIGNvdmlkX05QWGRhdGEgJT4lIAogIGZpbHRlcighQXNzYXklaW4lYXNzYXlzMnJtLCBUaW1lcG9pbnQ9PSJEMCIpICU+JQogIGRwbHlyOjpzZWxlY3QoU2FtcGxlSUQsIHN1YmplY3RfaWQsIEFzc2F5LCBOUFgsIFBhbmVsKQoKIyBpZGVudGlmeSBwcm90ZWlucyB3aXRoIGRpZmZlcmVudCB2YWx1ZXMgaW4gZGlmZmVyZW50IHBhbmVscwphc3NheXMycm0gPC0gY292aWRfTlBYZGF0YV9ybSAlPiUKICBncm91cF9ieShzdWJqZWN0X2lkLCBBc3NheSkgJT4lCiAgc3VtbWFyaXNlKG4gPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGZpbHRlcihuID4gMUwpICU+JQogIHB1bGwoQXNzYXkpICU+JQogIHVuaXF1ZSgpCgojIG9uZSBleGFtcGxlIG9mIHRoZSBwcm90ZWlucyBpZGVudGlmaWVkIGFib3ZlCmNvdmlkX05QWGRhdGFfcm0gJT4lIGZpbHRlcihzdWJqZWN0X2lkPT0xLEFzc2F5PT0iQ1hDTDgiKQoKIyBjb252ZXJ0IGRhdGEgdG8gd2lkZSBmb3JtYXQKY292aWRfTlBYZGF0YV93aWRlIDwtIGNvdmlkX05QWGRhdGFfcm0gJT4lCiAgIyMgdmFsdWVzX2ZuIGNhbGN1bGF0ZXMgbWVkaWFuIHZhbHVlcyBmb3IgZHVwbGljYXRlZCBmZWF0dXJlcyAoZHVwbGljYXRlZCBiZWNhdXNlIHBhcnQgb2YgZXZlcnkgb2xpbmsgcGFuZWwpCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEFzc2F5LCB2YWx1ZXNfZnJvbSA9IE5QWCxpZF9jb2xzID0gc3ViamVjdF9pZCwgdmFsdWVzX2ZuID0gbWVkaWFuKQoKIyBtYWtlIGRhdGEgcmVhZHkgZm9yIEdTVkEKY292aWRfTlBYZGF0YV9tYXQgPC0gY292aWRfTlBYZGF0YV93aWRlICU+JSAgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdWJqZWN0X2lkIikgJT4lCiAgYXMubWF0cml4KCkgJT4lIAogIHQoKQpgYGAKCgpgYGB7cn0KIyMjIyBSdW4gc2luZ2xlIHNhbXBsZSBnZW5lIHNldCBlbnJpY2htZW50IGFuYWx5c2lzCgpsaWJyYXJ5KEdTVkEpCgojIHJ1biBzc2dzZWEgb24gc2lnbmF0dXJlIGZyb20gc1BMU0RBCkdTRV9yZXN1bHRzIDwtIGdzdmEoZXhwciA9IGNvdmlkX05QWGRhdGFfbWF0LAogICAgICAgICAgICAgICAgICAgIGdzZXQuaWR4Lmxpc3QgPSBsaXN0KHNpZz1wbHNkYS5zZWxlY3Rpb24pLHZlcmJvc2U9RiwKICAgICAgICAgICAgICAgICAgICBtZXRob2Q9InpzY29yZSIpCgojZGF0YV9wbG90X3NQTFNEQSA8LSBkYXRhLmZyYW1lKGdyb3VwPWFzLmZhY3Rvcihjb3ZpZF9jbGluaWNhbERhdGEkV0hPLjApLHNjb3JlPWFzLnZlY3RvcihHU0VfcmVzdWx0cykpCgpHU0VBX3Jlc3VsdF9kZiA8LSBkYXRhLmZyYW1lKHN1YmplY3RfaWQgPSBjb2xuYW1lcyhjb3ZpZF9OUFhkYXRhX21hdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3NFUyA9IGFzLnZlY3RvcihHU0VfcmVzdWx0cykpICU+JSAKICByaWdodF9qb2luKG1naC5jb3ZpZC5tZXRhICU+JSB0cmFuc211dGUoc3ViamVjdF9pZD0gYXMuY2hhcmFjdGVyKHN1YmplY3RfaWQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aG9fMCA9IGFzLmZhY3Rvcih3aG9fMCkpLCBieT0ic3ViamVjdF9pZCIpCgojIHNob3cgcmVzdWx0cwooTUdIX2NvdmlkX3NzRVMgPC0gR1NFQV9yZXN1bHRfZGYgJT4lIAogIGdncGxvdChhZXMoeD13aG9fMCwgeT1zc0VTLCBmaWxsPXdob18wKSkgKwogICAgZ2VvbV9qaXR0ZXIod2lkdGg9MC4xNSxzaXplPS4zLGFscGhhPS4yKSArCiAjIGdlb21fdmlvbGluKHdpZHRoPTEuNSwgdHJpbSA9IEYsIGFscGhhPTAuNyxzaG93LmxlZ2VuZCA9IEYsbHdkPS4yNSkgKwogIGdlb21fYm94cGxvdCh3aWR0aD0uMyxhbHBoYT0uNiwgZmF0dGVuID0gMixsd2Q9LjI1LG91dGxpZXIuY29sb3VyID0gTkEpICsKICAjZ2VvbV9ib3hwbG90KGFscGhhPTAuNiwgd2lkdGg9LjIsIHNob3cubGVnZW5kID0gRikrCiAgdGhlbWVfbWluaW1hbCgpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh5PSJzc0VTIHNjb3JlICh6c2NvcmUpIix4PSJTZXZlcml0eSBncm91cCIsZmlsbD0iIikpCgpgYGAKCiMjIEZpZ3VyZSA2RQoKCmBgYHtyfQojIyMjIE1ha2UgZGF0YSByZWFkeQoKTUlQLmxvbmcgPC0gZGF0YS5sb25nICU+JSAKICBsZWZ0X2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlKSAlPiUKICBmaWx0ZXIoIWdyZXBsKCJEMTAiLHNhbXBsZV9pZCkpICU+JSAKICAgIGxlZnRfam9pbihwYXRpZW50X2NsdXN0KSAlPiUgCiAgbXV0YXRlKHNhbXBsZV90eXBlID0gY2FzZV93aGVuKFRpbWU9PSJBY3V0ZSIgfiBwYXN0ZTAoc2V2ZXJpdHlfbGFiLCIgbWFsYXJpYSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHBhc3RlMCgjVGltZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWFsYXJpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiBjb252YWxlc2NlbmNlIikpKSAlPiUgCiAgdHJhbnNtdXRlKHNhbXBsZV9pZCwgc2FtcGxlX3R5cGUsIEFzc2F5LCBOUFgpCgoKZGF0YV90Zl9taXBfd2lkZSA8LSBURi5sb25nICU+JSAKICBiaW5kX3Jvd3MoTUlQLmxvbmcpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQXNzYXksIHZhbHVlc19mcm9tID0gTlBYLCBpZF9jb2xzID0gYyhzYW1wbGVfaWQsc2FtcGxlX3R5cGUpLCB2YWx1ZXNfZm4gPSBtZWRpYW4pIAoKYWxsLm1hdCA8LSBkYXRhX3RmX21pcF93aWRlICU+JQogIGRwbHlyOjpzZWxlY3QoLWMoc2FtcGxlX3R5cGUpKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGVfaWQiKSAlPiUgCiAgYXMubWF0cml4KCkgJT4lIAogIHQoKQpgYGAKCgpgYGB7cn0KIyMjIyBSdW4gc2luZ2xlIHNhbXBsZSBnZW5lIHNldCBlbnJpY2htZW50IGFuYWx5c2lzCmxpYnJhcnkoR1NWQSkKIyBydW4gc3Nnc2VhIG9uIHNpZ25hdHVyZSBmcm9tIHNQTFNEQQpHU0VfcmVzdWx0cyA8LSBnc3ZhKGV4cHIgPSBhbGwubWF0LAogICAgICAgICAgICAgICAgICAgIGdzZXQuaWR4Lmxpc3QgPSBsaXN0KHNpZz1wbHNkYS5zZWxlY3Rpb24pLCNsaXN0KHNpZz1zZXZlcml0eV9zaWduYXR1cmVfcHJvdGVpbnMpLAogICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9RiwKICAgICAgICAgICAgICAgICAgICBtZXRob2Q9InpzY29yZSIpCgoKR1NFQV9yZXN1bHRfZGYgPC0gZGF0YS5mcmFtZShzYW1wbGVfaWQgPSBjb2xuYW1lcyhhbGwubWF0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzc0VTID0gYXMudmVjdG9yKEdTRV9yZXN1bHRzKSkgJT4lIAogIGxlZnRfam9pbihkYXRhX3RmX21pcF93aWRlICU+JSBkcGx5cjo6c2VsZWN0KHNhbXBsZV9pZCxzYW1wbGVfdHlwZSksIGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgbGVmdF9qb2luKAogIFRGX1NPRkEgJT4lIHRyYW5zbXV0ZShzYW1wbGVfaWQgPSBwYXN0ZTAoc3R1ZHlfaWQsInxBY3V0ZSIpLCBTT0ZBX3RvdGFsKSAlPiUKICBiaW5kX3Jvd3MoCiAgICBzdWJqZWN0VGFibGUgJT4lIHRyYW5zbXV0ZShzYW1wbGVfaWQgPSBwYXN0ZTAoc3R1ZHlfaWQsInxBY3V0ZSIpLCBTT0ZBX3RvdGFsKQogICkpICU+JSAKICBtdXRhdGUoc2FtcGxlX3R5cGUgPSBjYXNlX3doZW4oc2FtcGxlX3R5cGUgPT0gIkluZmx1ZW5zYSBBIiB+ICJJbmZsdWVuemEgQSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZV90eXBlID09ICJJbmZsdWVuc2EgQiIgfiAiSW5mbHVlbnphIEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHNhbXBsZV90eXBlKSkKCiMgc2hvdyByZXN1bHRzCgooVEZfc3NFU19wbG90IDwtIEdTRUFfcmVzdWx0X2RmICU+JSAKZ2dwbG90KGFlcyh4PWZjdF9yZW9yZGVyKHNhbXBsZV90eXBlLHNzRVMsIG1lZGlhbiwuZGVzYyA9IFQpLCB5PXNzRVMsIGZpbGw9c2FtcGxlX3R5cGUpKSArCiAgZ2VvbV9qaXR0ZXIod2lkdGg9MC4xNSxzaXplPS4zLGFscGhhPS4yKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPS4zLGFscGhhPS42LCBmYXR0ZW4gPSAyLGx3ZD0uMjUsb3V0bGllci5jb2xvdXIgPSBOQSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Yygic2V2ZXJlIG1hbGFyaWEiPXBhdGllbnRfa2NsdXN0M19sYWJbWzNdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtb2RlcmF0ZSBtYWxhcmlhIj1wYXRpZW50X2tjbHVzdDNfbGFiW1syXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWlsZCBtYWxhcmlhIj1wYXRpZW50X2tjbHVzdDNfbGFiW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWFsYXJpYSBjb252YWxlc2NlbmNlIj1wYXRpZW50X2tjbHVzdDNfbGFiX2NvbnZbWzRdXSksCiAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICIjOGRkM2M3IikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsbGluZXR5cGU9ImRvdHRlZCIpICsKICBsYWJzKHRpdGxlPSJFdmFsdWF0aW9uIG9mIG1hbGFyaWEgZGlzZWFzZSBzZXZlcml0eSBzaWduYXR1cmUiLAogICAgICAgeD1OVUxMLAogICAgICAgeT0iR2VuZSBTZXQgVmFyaWF0aW9uIEFuYWx5c2lzXG5zaW5nbGUgc2FtcGxlIGVucmljaG1lbnQgc2NvcmVcbih6c2NvcmUpIiwKICAgICAgIGZpbGw9IiIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGxhYmVsX3dyYXAoOCkpICkKCmBgYAoKIyMgU3VwcGxlbWVudGFyeSBUYWJsZSBTNQoKYGBge3J9Cm1hbGFyaWEuc2V2ZXJpdHkuc2lnYW50dXJlICU+JSAKICBhcnJhbmdlKHZhbHVlcykgJT4lIAogIGRwbHlyOjpyZW5hbWUoaW1wb3J0YW5jZSA9IHZhbHVlcykgJT4lIAogIGhlYWQoKQogICN3cml0ZV90c3YocGFzdGUwKHJlc3VsdC5kaXIsIlN1cHBsZW1lbnRhcnlfVGFibGVTNV9TZXZlcml0eVNpZ25hdHVyZS50c3YiKSkKYGBgCgojIyBTdXBwbGVtZW50YXJ5IFRhYmxlIFM2IApURiBjb2hvcnQgLSBzYW1wbGVUYWJsZQoKYGBge3J9CiMjZ3RzdW1tYXJ5CmxpYnJhcnkoZ3RzdW1tYXJ5KQoKVEZfc2FtcGxlVGFibGUgJT4lIAogIGRwbHlyOjpzZWxlY3QoLXNhbXBsZV90eXBlKSAlPiUgCiAgaW5uZXJfam9pbihHU0VBX3Jlc3VsdF9kZiwgYnk9InNhbXBsZV9pZCIpICU+JSAKICB0cmFuc211dGUoc2FtcGxlX3R5cGUsIAogICAgICAgICAgICBTT0ZBX3RvdGFsID0gYXMubnVtZXJpYyhTT0ZBX3RvdGFsKSwKICAgICAgICAgICAgYWdlID0gYXMubnVtZXJpYyhhZ2UpLAogICAgICAgICAgICBnZW5kZXIpICU+JSAKICBmaWx0ZXIoIWdyZXBsKCJNYWxhcmlhfG1hbGFyaWEiLCBzYW1wbGVfdHlwZSkpICU+JSAKICAKICB0Ymxfc3VtbWFyeShpbmNsdWRlID0gYyhzYW1wbGVfdHlwZSwgYWdlLCBnZW5kZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgU09GQV90b3RhbCksCiAgICAgICAgICAgICAgYnkgPSBzYW1wbGVfdHlwZSwKICAgICAgICAgICAgICBzdGF0aXN0aWMgPSBsaXN0KGFsbF9jb250aW51b3VzKCkgfiAie21lZGlhbn0gKHttaW59LXttYXh9KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGxfY2F0ZWdvcmljYWwoKSB+ICJ7bn0gLyB7Tn0gKHtwfSUpIgogICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgI2RpZ2l0cyA9IGFsbF9jb250aW51b3VzKCkgfiAyCiAgICAgICAgICAgICAgZGlnaXRzID0gYyhhZ2UgfiAwKQogICAgICAgICAgICAgICkKYGBgCgoKCiMgRmlndXJlIDcgCioqQSBwcm90ZWluLWNlbnRyaWMgdmlldyBvbiBpbnRlZ3JhdGVkIGFuYWx5c2lzIHRvIGFzY2VydGFpbiBpbW11bmUgY2VsbCBjb21tdW5pY2F0aW9uIGFzc29jaWF0ZWQgd2l0aCBkaXNlYXNlIHNldmVyaXR5KioKCgojIyBGaWd1cmUgN0EKYGBge3J9CnNpbWlsYXJfbW9kdWxlcyA8LSBjKHJlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZSwKICAgICAgICAgICAgICAgICAgICAgbW9kdWxlX2RmICU+JSBmaWx0ZXIoY29sb3JzPT0iYnJvd24iKSAlPiUgcHVsbChBc3NheSksCiAgICAgICAgICAgICAgICAgICAgIG1vZHVsZV9kZiAlPiUgZmlsdGVyKGNvbG9ycz09ImJsdWUiKSAlPiUgcHVsbChBc3NheSkpCmxpYnJhcnkoZXVsZXJyKQpldWxlcl9wbG90IDwtIGV1bGVyKAogIGxpc3QoCiAgICAiRGlmZmVyZW50aWFsXG5hYnVuZGFudFxucHJvdGVpbnNcbmluXG5hY3V0ZSBtYWxhcmlhIj1zZWxlY3RlZC5hc3NheXMud2NuYSwKICAgICJTZXZlcml0eSBhc3NvY2lhdGVkXG5wcm90ZWlucyBpbiBwbGFzbWEiID0gcmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlKQopCgpwbG90KGV1bGVyX3Bsb3QsCiAgICAgZmlsbHMgPSBjKCJ3aGl0ZSIsCiAgICAgICAgICAgICAgICJ0dXJxdW9pc2UiKSwKICAgICAgICAgICAgICAgCiAgICAgcXVhbnRpdGllcyA9IFRSVUUsCiAgICAgbHR5ID0gMSwjMTozLAogICAgIGZvbnRzaXplPTYsCiAgICAgbGFiZWxzID0gbGlzdChmb250c2l6ZT01KSwKICAgICBzaGFwZSA9ICJlbGxpcHNlIikgCgpgYGAKCgojIyBGaWd1cmUgN0IKCmBgYHtyfQpzZWNyZXRvbWVfbG9jYXRpb25fZGFwX3NldmVyaXR5IDwtIGRhcC5yZXMgJT4lIAogIGZpbHRlcihBc3NheSAlaW4lIHJlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZSkgJT4lIAogIGlubmVyX2pvaW4oaHBhXzI0LjAsIGJ5PWMoIkFzc2F5Ij0iZ2VuZSIsIlVuaVByb3QiPSJ1bmlwcm90IikpICU+JSAKICBtdXRhdGUoc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjID0gY2FzZV93aGVuKHNlY3JldG9tZV9sb2NhdGlvbj09Ik5vdCBzZWNyZXRlZCJ+IHBhc3RlMChzZWNyZXRvbWVfbG9jYXRpb24sIiAtICIscm5hX3Rpc3N1ZV9zcGVjaWZpY2l0eSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gc2VjcmV0b21lX2xvY2F0aW9uKSkgJT4lIAogIGdyb3VwX2J5KHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykgJT4lIAogbXV0YXRlKG5fc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjID0gbigpKSAjY291bnQoc29ydCA9IFRSVUUpIAoKCiMjIHBsb3QgZXZlcnl0aGluZwooaHBhLnByb3RlaW4ub3JpZ2luLm92ZXJ2aWV3X3NldmVyaXR5IDwtIHNlY3JldG9tZV9sb2NhdGlvbl9kYXBfc2V2ZXJpdHkgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIHRyYW5zbXV0ZShzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMgPSBmYWN0b3Ioc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHJldihjKCJTZWNyZXRlZCB0byBibG9vZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkludHJhY2VsbHVsYXIgYW5kIG1lbWJyYW5lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gb3RoZXIgdGlzc3VlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIHRvIGV4dHJhY2VsbHVsYXIgbWF0cml4IiwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCB0byBkaWdlc3RpdmUgc3lzdGVtIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIGJyYWluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgLSB1bmtub3duIGxvY2F0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gZmVtYWxlIHJlcHJvZHVjdGl2ZSBzeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCBpbiBtYWxlIHJlcHJvZHVjdGl2ZSBzeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBUaXNzdWUgZW5yaWNoZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm90IHNlY3JldGVkIC0gVGlzc3VlIGVuaGFuY2VkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm90IHNlY3JldGVkIC0gR3JvdXAgZW5yaWNoZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBMb3cgdGlzc3VlIHNwZWNpZmljaXR5IikpKSwKICAgICAgICAgICAgICBuX3NlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykgJT4lIAogICAgZGlzdGluY3QoKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMsIHkgPSBuX3NlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYywgZmlsbCA9IHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykpICsKICAgIGdlb21fY29sKHdpZHRoID0gMC41KSArCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsPW5fc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSxzaXplPTIsIG51ZGdlX3kgPSAtLjIpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9InBzZXVkb19sb2ciLG5hbWUgPSAiTnVtYmVyIG9mIHByb3RlaW5zXG5hc3NvY2lhdGVkIHdpdGggc2V2ZXJpdHkiLAogICAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4sbGFiZWxzID0gTlVMTCxicmVha3MgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI25hbWUgPSAiTnVtYmVyIG9mIERBUHMiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLCAKICAgICAgICAgICAgICAgICAgICAgICAjZXhwYW5kPWMoMCwuMTUpCiAgICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gYygwLDApCiAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsKCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9c2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjX2NvbHMsCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBzZWNyZXRvbWVfbG9jYXRpb25fZGFwLm9yZGVyKSArCiAgICBsYWJzKGZpbGw9IlByb3RlaW5cbm9yaWdpblxuYnkgSFBBIiwKICAgICAgICAgeD1OVUxMKSkKCiMjIHBsb3QgZXZlcnl0aGluZwooaHBhLnByb3RlaW4ub3JpZ2luLm92ZXJ2aWV3X3NldmVyaXR5IDwtIHNlY3JldG9tZV9sb2NhdGlvbl9kYXBfc2V2ZXJpdHkgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIHRyYW5zbXV0ZShzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMgPSBmYWN0b3Ioc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlNlY3JldGVkIHRvIGJsb29kIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW50cmFjZWxsdWxhciBhbmQgbWVtYnJhbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCBpbiBvdGhlciB0aXNzdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgdG8gZXh0cmFjZWxsdWxhciBtYXRyaXgiLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIHRvIGRpZ2VzdGl2ZSBzeXN0ZW0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gYnJhaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCAtIHVua25vd24gbG9jYXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCBpbiBmZW1hbGUgcmVwcm9kdWN0aXZlIHN5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIG1hbGUgcmVwcm9kdWN0aXZlIHN5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdCBzZWNyZXRlZCAtIFRpc3N1ZSBlbnJpY2hlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBUaXNzdWUgZW5oYW5jZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBHcm91cCBlbnJpY2hlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdCBzZWNyZXRlZCAtIExvdyB0aXNzdWUgc3BlY2lmaWNpdHkiKSksCiAgICAgICAgICAgICAgbl9zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpICU+JSAKICAgIGRpc3RpbmN0KCkgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjLCB5ID0gbl9zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMsIGZpbGwgPSBzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpKSArCiAgICBnZW9tX2NvbCh3aWR0aCA9IDAuNSkgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1uX3NlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyksc2l6ZT0yLCBudWRnZV95ID0xLjUpICsgIzAuMQogICAgI2Nvb3JkX2ZsaXAoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoI3RyYW5zPSJwc2V1ZG9fbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIk51bWJlciBvZiBwcm90ZWlucyIsCiAgICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LixsYWJlbHMgPSBOVUxMLGJyZWFrcyA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjbmFtZSA9ICJOdW1iZXIgb2YgREFQcyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksIAogICAgICAgICAgICAgICAgICAgICAgICNleHBhbmQ9YygwLC4xNSkKICAgICAgICAgICAgICAgICAgICAgICAjZXhwYW5kID0gYygwLDAuMSksCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLDUxKQogICAgICAgICAgICAgICAgICAgICAgICkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNixhbmdsZT05MCxoanVzdCA9IDEsdmp1c3QgPSAwLjUpLAogICAgICAgICAgI2F4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LGFuZ2xlPTQ1LGhqdXN0ID0gMSksCiAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKCiAgICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrCgogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlY19jb2xzLAogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gc2VjcmV0b21lX2xvY2F0aW9uX2RhcC5vcmRlcikgKwogICAgbGFicyhmaWxsPSJQcm90ZWluXG5vcmlnaW5cbmJ5IEhQQSIsCiAgICAgICAgIHg9TlVMTCkpCmBgYAoKIyMgRmlndXJlIDdDCmBgYHtyfQpwcm90ZWluczJsYWJlbCA8LSBkZl9hY3V0ZV9wYXRjbHVzdF9pbmNsX2NvbnYgJT4lIAogIGdyb3VwX2J5KFVuaVByb3QsQXNzYXksIHNldmVyaXR5X2xhYikgJT4lIAogIHN1bW1hcmlzZShOUFhtZWFuID0gbWVhbihOUFgpLAogICAgICAgICAgICBOUFhtZWRpYW4gPSBtZWRpYW4oTlBYKSwKICAgICAgICAgICAgTlBYc2QgPSBzZChOUFgpLAogICAgICAgICAgICBOUFhuID0gbigpLAogICAgICAgICAgICBOUFhzZSA9IE5QWHNkIC8gc3FydChOUFhuKQogICkgJT4lIAogICN1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShOUFhjaTk1ID0gTlBYc2UgKiBxdCguOTc1LCBOUFhuIC0gMSkpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBzZWNyZXRvbWVfbG9jYXRpb25fZGFwX3NldmVyaXR5ICU+JQogICAgZmlsdGVyKEFzc2F5ICVpbiUgcmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlKSAlPiUKICB0cmFuc211dGUoQXNzYXksc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSwgYnk9IkFzc2F5IgogICkgJT4lIAogIGZpbHRlcihzZXZlcml0eV9sYWI9PSJzZXZlcmUiLAogICAgICAgICBBc3NheSAlaW4lIHJlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZSwKICAgICAgICAgIWlzLm5hKHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykpICU+JSAKICAKICBncm91cF9ieShzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpICU+JSAKICAjdHJhbnNtdXRlKEFzc2F5LE5QWCwgc2V2ZXJpdHlfbGFiLCBzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBzbGljZV9tYXgob3JkZXJfYnkgPSBOUFhtZWFuLG4gPSAzKSAlPiUgcHVsbChBc3NheSkKYGBgCgoKCmBgYHtyIGZpZy5oZWlnaHQgPSAxLjUsIGZpZy53aWR0aD0gNH0KdG1wLmRmIDwtIGRmX2FjdXRlX3BhdGNsdXN0X2luY2xfY29udiAlPiUgCiAgZ3JvdXBfYnkoVW5pUHJvdCxBc3NheSwgc2V2ZXJpdHlfbGFiKSAlPiUgCiAgc3VtbWFyaXNlKE5QWG1lYW4gPSBtZWFuKE5QWCksCiAgICAgICAgICAgIE5QWG1lZGlhbiA9IG1lZGlhbihOUFgpLAogICAgICAgICAgICBOUFhzZCA9IHNkKE5QWCksCiAgICAgICAgICAgIE5QWG4gPSBuKCksCiAgICAgICAgICAgIE5QWHNlID0gTlBYc2QgLyBzcXJ0KE5QWG4pCiAgKSAlPiUgCiAgI3VuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKE5QWGNpOTUgPSBOUFhzZSAqIHF0KC45NzUsIE5QWG4gLSAxKSkgJT4lIAogIGZpbHRlcihBc3NheSVpbiVyZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBzZWNyZXRvbWVfbG9jYXRpb25fZGFwX3NldmVyaXR5JT4lIAogICAgICB0cmFuc211dGUoQXNzYXksIHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyksIGJ5PSJBc3NheSIpCgoodHVycW9pc2VfYWxsUHJvdGVpbnNfbGFiIDwtIHRtcC5kZiAlPiUgCiAgZ2dwbG90KGFlcyh4PWZjdF9yZW9yZGVyKEFzc2F5LE5QWG1lYW4sLmRlc2MgPSBGKSwgeT1OUFhtZWFuKSkgKwogIGdlb21fcG9pbnQoc2hhcGU9MTYsc2l6ZT0uNSxhZXMoY29sb3I9c2V2ZXJpdHlfbGFiKSkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHggPSBBc3NheSwjcmVvcmRlcihzdHJfd3JhcChBc3NheSwgNSksIGVzdGltYXRlKSwKICAgICAgICAgICAgICAgICAgICB5bWluPU5QWG1lYW4tTlBYY2k5NSwgCiAgICAgICAgICAgICAgICAgICAgeW1heD1OUFhtZWFuK05QWGNpOTUsCiAgICAgICAgICAgICAgICAgICAgY29sb3I9c2V2ZXJpdHlfbGFiKSwKICAgICAgICAgICAgICAgIGxpbmV3aWR0aD0uMiwgICAgIyBUaGlubmVyIGxpbmVzCiAgICAgICAgICAgICAgICB3aWR0aD0uMiwKICAgICAgICAgICAgICAgIGFscGhhPS41KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCxsdHk9NSwgbHdkPS4yKSArCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YSA9IC4gJT4lIGZpbHRlcihBc3NheSAlaW4lIHByb3RlaW5zMmxhYmVsLCNjKCJMR0FMUzkiLCJIQVZDUjIiLCJJTDQiLCJJTDRSIiwiQ0Q3MCIsIlBEQ0QxIiwiQ0QyNzQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldmVyaXR5X2xhYiA9PSAic2V2ZXJlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gQXNzYXksIGNvbG91cj1zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMsIG51ZGdlX3k9TlBYbWVhbiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IC45LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlX3B1bGwgPSAzLCAjIGRvIG5vdCBwdWxsIHRvd2FyZCBkYXRhIHBvaW50cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlID0gLjE1LCAjIFN0cmVuZ3RoIG9mIHRoZSByZXB1bHNpb24gZm9yY2UuCgogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgRG8gbm90IHJlcGVsIGZyb20gdG9wIG9yIGJvdHRvbSBlZGdlcy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGltID0gYygxLCBJbmYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJ5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCAgICAgICAgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDEvMjAsICAgICMjIHNlZ21lbnQgd2lkdGgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LmxpbmV3aWR0aCA9IDEvMTIsIzAuMDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMDQsICducGMnKSksICAgICAjIERyYXcgYW4gYXJyb3cgZnJvbSB0aGUgbGFiZWwgdG8gdGhlIGRhdGEgcG9pbnQuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gNTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Lml0ZXIgPSAzZTMsICAgICAjIE1heGltdW0gaXRlcmF0aW9ucyBvZiB0aGUgbmFpdmUgcmVwdWxzaW9uIGFsZ29yaXRobSBPKG5eMikuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleTEwIgogICkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9YygtMS41LDguNSksZXhwYW5kID0gYygwLDApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhdGllbnRfa2NsdXN0M19sYWJfY29udikgKwogICAgICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKSArCgogICNjb29yZF9mbGlwKCkgKwogIAogIGxhYnMoeD0iU2V2ZXJpdHkgYXNzb2NpYXRlZCBwcm90ZWlucyBpbiBwbGFzbWEiLAogICAgICAgeT0iTlBYIiwKICAgICAgIGNvbG9yPU5VTEwsCiAgICAgICBjYXB0aW9uID0gIm1lYW5OUFggKy0gY2k5NSIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLGFuZ2xlPTkwLGhqdXN0PTEsdmp1c3Q9LjUsc2l6ZSA9IDIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjEpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IC4xKSwKICAgICAgICAjYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICApCikKCnJlcXVpcmUocGF0Y2h3b3JrKQoocF9hbm5vdGF0aW9uIDwtICNzZWNyZXRvbWVfbG9jYXRpb25fZGFwX3NldmVyaXR5JT4lIAogICAgI3RyYW5zbXV0ZShBc3NheSwgc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSAlPiUgCiAgICMgbGVmdF9qb2luKHRtcC5kZixieT0iQXNzYXkiKSAlPiUgCiAgICB0bXAuZGYgJT4lIAogICAgbXV0YXRlKGR1bW15LnkgPSAiSFBBIikgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gZmN0X3Jlb3JkZXIoQXNzYXksTlBYbWVhbiwuZGVzYyA9IEYpLCB5ID0gZHVtbXkueSwgZmlsbCA9IHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykpICsKICAgIGdlb21fdGlsZShsaW5lam9pbiA9ICJyb3VuZCIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlY19jb2xzKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAKICAjc2NhbGVfeV9kaXNjcmV0ZShleHBhbmQ9YygwLC0wLjEpKQogICAjIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEvMTAwKQogICkKCnRlc3RfcGxvdCA8LSBwX2Fubm90YXRpb24gLyB0dXJxb2lzZV9hbGxQcm90ZWluc19sYWIgKyBwbG90X2xheW91dChoZWlnaHQgPSBjKC41LCA0KSkKdGVzdF9wbG90CmBgYAoKCiMjIEZpZ3VyZSA3RAoKYGBge3J9CiMjIGNyZWF0ZSBhIGdlbmUgbmFtZSAtIHVuaXByb3QgZGljdGlvbmFyeQpuYW1lX3VwX2RpY3QgPC0gaHBhXzI0LjAgJT4lIHRyYW5zbXV0ZShnZW5lLCB1bmlwcm90KQoKbGlnYW5kLnEgPC0gZGFwLnJlcyAlPiUgZmlsdGVyKHAuYWRqIDw9MC4wMSwgbG9nRkMgPiAuMSkgJT4lIAogIGxlZnRfam9pbihjcGRiLnByb3RlaW5faW5wdXQsCiAgICAgICAgICAgIGJ5PWMoIlVuaVByb3QiPSJ1bmlwcm90IikpICMlPiUgCiAgI3B1bGwoVW5pUHJvdCkKCmxlbmd0aChsaWdhbmQucSkKCgppbnRlcmFjdGlvbl9kaWN0IDwtIGNwZGIuaW50ZXJhY3Rpb25faW5wdXQgJT4lIAogIGZpbHRlcihwYXJ0bmVyX2EgJWluJSBsaWdhbmQucSRVbmlQcm90LAogICAgICAgICBkaXJlY3Rpb25hbGl0eSA9PSAiTGlnYW5kLVJlY2VwdG9yIgogICAgICAgICNkaXJlY3Rpb25hbGl0eSAlaW4lIGMoIkxpZ2FuZC1SZWNlcHRvciIsIlJlY2VwdG9yLVJlY2VwdG9yIiwiTGlnYW5kLUxpZ2FuZCIpCiAgICAgICAgICkgJT4lIAogIG11dGF0ZShwcm90ZWluX25hbWVfYl9zdHJpcCA9IGdzdWIoIl9IVU1BTiIsIiIscHJvdGVpbl9uYW1lX2IpLAogICAgICAgICBwcm90ZWluX25hbWVfYSA9IGdzdWIoIl9IVU1BTiIsIiIscHJvdGVpbl9uYW1lX2EpKSAlPiUgCiAgbXV0YXRlKHByb3RlaW5fbmFtZV9iX2NvbXBsZXggPSBjYXNlX3doZW4oaXMubmEocHJvdGVpbl9uYW1lX2IpIH4gc3RyX3JlbW92ZShpbnRlcmFjdG9ycyxwYXN0ZTAocHJvdGVpbl9uYW1lX2EsIi0iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gcHJvdGVpbl9uYW1lX2IpKSAlPiUKICAgc2VwYXJhdGVfbG9uZ2VyX2RlbGltKHByb3RlaW5fbmFtZV9iX2NvbXBsZXgsIGRlbGltID0gIisiKSAlPiUgCiAgIGxlZnRfam9pbihocGFfMjQuMCAlPiUgdHJhbnNtdXRlKHByb3RlaW5fbmFtZV9iX2NvbXBsZXggPSBnZW5lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXByb3RfYl9jb21wbGV4ID0gdW5pcHJvdCksIGJ5PWMoInByb3RlaW5fbmFtZV9iX2NvbXBsZXgiKSkgJT4lIAogIG11dGF0ZShwcm90ZWluX25hbWVfYiA9IGNhc2Vfd2hlbihpcy5uYShwcm90ZWluX25hbWVfYikgfiBwcm90ZWluX25hbWVfYl9jb21wbGV4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBwcm90ZWluX25hbWVfYiksCiAgICAgICAgIHBhcnRuZXJfYl9uZXcgPSBjYXNlX3doZW4oaXMubmEodW5pcHJvdF9iX2NvbXBsZXgpIH4gcGFydG5lcl9iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gdW5pcHJvdF9iX2NvbXBsZXgpKSAlPiUgCiAgdHJhbnNtdXRlKHBhcnRuZXJfYSwgcGFydG5lcl9iLCBwYXJ0bmVyX2JfbmV3KSAlPiUgCiAgbXV0YXRlKHVuaXByb3RfYSA9IHBhcnRuZXJfYSwKICAgICAgICAgdW5pcHJvdF9iID0gcGFydG5lcl9iX25ldykgJT4lIAogIHRyYW5zbXV0ZShzb3VyY2UgPSB1bmlwcm90X2EsCiAgICAgICAgICAgIHJlY2lwaWVudCA9IHVuaXByb3RfYikgJT4lIAogIGxlZnRfam9pbihuYW1lX3VwX2RpY3QgJT4lIGRwbHlyOjpyZW5hbWUoc291cmNlX2dlbmUgPSBnZW5lKSwgYnk9Yygic291cmNlIiA9ICJ1bmlwcm90IikpICU+JSAKICBsZWZ0X2pvaW4obmFtZV91cF9kaWN0ICU+JSBkcGx5cjo6cmVuYW1lKHJlY2lwaWVudF9nZW5lID0gZ2VuZSksIGJ5PWMoInJlY2lwaWVudCIgPSAidW5pcHJvdCIpKQppbnRlcmFjdGlvbl9kaWN0CmBgYAoKYGBge3J9CgpjZWxsdHlwZV9sMl9mcmVxIDwtIHRpYmJsZShwYm1jX2FjdXRlQG1ldGEuZGF0YSkgJT4lIAogIGdyb3VwX2J5KENlbGxUeXBlX0wyKSAlPiUgCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQogIG11dGF0ZShmcmVxID0gbiAvIHN1bShuKSwKICAgICAgICAgUGVyY2VudGFnZSA9IGZyZXEqMTAwKSAKCmNlbGx0eXBlX2wyX29mX2wxX2ZyZXEgPC0gdGliYmxlKHBibWNfYWN1dGVAbWV0YS5kYXRhKSAlPiUgCiAgZ3JvdXBfYnkoQ2VsbFR5cGVfTDEsQ2VsbFR5cGVfTDIpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lCiAgZ3JvdXBfYnkoQ2VsbFR5cGVfTDEpICU+JSAKICBtdXRhdGUoZnJlcSA9IG4gLyBzdW0obiksCiAgICAgICAgIFBlcmNlbnRhZ2UgPSBmcmVxKjEwMCkgCgpgYGAKCgoKY2lyY29zcGxvdCBmdW5jdGlvbgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbXlfbmljZV9jaXJjb3NwbG90IDwtIGZ1bmN0aW9uKGFzc2F5czJwbG90X2NpcmNvcywgc2NhbGVfcmFuZ2UsIGV4cHJlc3Npb25fdGhyZXNob2xkLCBwZGZfZmlsZV9uYW1lKXsKICAKcGJtY19hY3V0ZS5hdmcubG9uZ190b3VycXVvaXNlIDwtIHBibWNfYWN1dGUuYXZnLmxvbmcgJT4lIAogIGZpbHRlcihjZWxsdHlwZSAhPSAidW5kZWZpbmVkIiwKICAgICAgICAgZ2VuZSAlaW4lIGFzc2F5czJwbG90X2NpcmNvcywKICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKGdlbmVfY3QgPSBwYXN0ZTAoZ2VuZSwiXyIsY2VsbHR5cGUpKSAlPiUgCiAgZ3JvdXBfYnkoZ2VuZSkgJT4lIAogIG11dGF0ZShhdmdFeHAgPSBzY2FsZXM6OnJlc2NhbGUoYXZnRXhwLCB0bz1zY2FsZV9yYW5nZSkpICU+JSAgI2MoMCwxKQogIHVuZ3JvdXAoKSAKCm1hdCA8LSBwYm1jX2FjdXRlLmF2Zy5sb25nX3RvdXJxdW9pc2UgJT4lIAogICAgZmlsdGVyKGF2Z0V4cCA+ZXhwcmVzc2lvbl90aHJlc2hvbGQpICU+JSAjLjUKICBsZWZ0X2pvaW4odGliYmxlKHBibWNAbWV0YS5kYXRhKSAlPiUgdHJhbnNtdXRlKGNlbGx0eXBlXzEgPSBDZWxsVHlwZV9MMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VsbHR5cGUgPSBDZWxsVHlwZV9MMikgJT4lIGRpc3RpbmN0KCksIGJ5PSJjZWxsdHlwZSIpICU+JSAKICBtdXRhdGUoY2VsbHR5cGVfMSA9IGZhY3RvcihjZWxsdHlwZV8xLCBsZXZlbHM9IGMoIkRDIiwiTW9ub2N5dGVzIiwiTksiLCJnZFQiLCJCIiwiQ0Q0KyBUIiwiQ0Q4KyBUIikpLAogICAgICAgICBjZWxsdHlwZSA9IGZhY3RvcihjZWxsdHlwZSwgbGV2ZWxzID0gYygibURDIiwgInBEQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0QxNCBtb25vY3l0ZXMiLCAiQ0QxNiBtb25vY3l0ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTksgQ0Q1NmRpbSBDRDE2KyIsICJOSyBDRDU2ZGltIiwiTksgQ0Q1NmJyaWdodCIsIk5LIHByb2xpZi4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmQyKyBnZFQiLCAiVmQyLSBnZFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQiBuYWl2ZSIsICJCIG1lbW9yeSIsICJQbGFzbWEgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0Q0IG5haXZlIiwgIkNENCBUcmVnIENEODArIiwgIkNENCBUcmVnIENEODAtIiwgIkNENCBUZmgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0Q0IGVmZmVjdC4gYWN0aXZhdGVkIiwgIkNENCBlZmZlY3QuIG1lbW9yeSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDQgdHJhbnMuIG1lbW9yeSIsIkNENCBjZW50cmFsIG1lbW9yeSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDggbmFpdmUiLCAiQ0Q4IHRyYW5zLiBtZW1vcnkiLCAiQ0Q4IFRmaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOS1QiLCAiQ0Q4IGVmZmVjdC4gbWVtb3J5IikpKSAlPiUgCiAgYWRkX3Jvd25hbWVzKCkgCgoKdG1wIDwtIG1hdCAlPiUgZHBseXI6OnJlbmFtZShpbmRleCA9IHJvd25hbWUpIAoKZGZfbGluayA8LSBpbnRlcmFjdGlvbl9kaWN0ICU+JSAKICB0cmFuc211dGUoc291cmNlX2dlbmUsIHJlY2lwaWVudF9nZW5lKSAlPiUgCiAgbGVmdF9qb2luKHRtcCAlPiUgCiAgICAgICAgICAgICAgIGZpbHRlcihnZW5lICVpbiUgaW50ZXJhY3Rpb25fZGljdCRzb3VyY2VfZ2VuZSkgJT4lCiAgICAgICAgICAgICAgIHRyYW5zbXV0ZShmcm9tX2luZGV4ID0gaW5kZXgsCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lKSwgCiAgICAgICAgICAgICBieT1jKCJzb3VyY2VfZ2VuZSI9ImdlbmUiKSkgJT4lIAogIGZpbHRlcighaXMubmEoZnJvbV9pbmRleCkpICU+JSAKICBsZWZ0X2pvaW4odG1wICU+JSAKICAgICAgICAgICAgICAgdHJhbnNtdXRlKHRvX2luZGV4ID0gaW5kZXgsCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lKSwgCiAgICAgICAgICAgICBieT1jKCJyZWNpcGllbnRfZ2VuZSI9ImdlbmUiKSkgJT4lIAogIGZpbHRlcighaXMubmEodG9faW5kZXgpKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgcmlnaHRfam9pbihtYXQgJT4lIHRyYW5zbXV0ZShnZW5lLCBjZWxsdHlwZSkgJT4lIAogICAgICAgICAgICAgICBsZWZ0X2pvaW4oZGF0YS5mcmFtZShjZWxsdHlwZSA9IG5hbWVzKEwyX2NvbG9ycyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VfY2VsbHR5cGVfY29sb3JzID0gTDJfY29sb3JzKSksCiAgICAgICAgICAgICAgYnk9Yygic291cmNlX2dlbmUiPSJnZW5lIikpICU+JSAKICAKICB0cmFuc211dGUoZnJvbV9pbmRleCA9IGFzLmludGVnZXIoZnJvbV9pbmRleCksCiAgICAgICAgICAgIHRvX2luZGV4ID0gYXMuaW50ZWdlcih0b19pbmRleCksCiAgICAgICAgICAgIHNvdXJjZV9jZWxsdHlwZSA9IGNlbGx0eXBlLAogICAgICAgICAgICBzb3VyY2VfZ2VuZSwKICAgICAgICAgICAgcmVjaXBpZW50X2dlbmUpICU+JSAKICBuYS5vbWl0KCkgJT4lIAogIGRpc3RpbmN0KCkKCiMjIGdvYWwKIyMgZnJvbV9pbmRleDsgdG9faW5kZXggZGF0YSBmcmFtZQoKCm1hdF9nZXggPC0gbWF0ICU+JSBhcnJhbmdlKGNlbGx0eXBlKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImdlbmVfY3QiKSAlPiUgCiAgZHBseXI6OnNlbGVjdChhdmdFeHApCgptYXRfbnB4IDwtIG1hdCAlPiUKICB0cmFuc211dGUoZ2VuZV9jdCwgZ2VuZSkgJT4lIAogIGxlZnRfam9pbihkZl9hY3V0ZV9wYXRjbHVzdF9pbmNsX2NvbnYgJT4lIAogICAgICAgICAgICAgIHRyYW5zbXV0ZShBc3NheSwgTlBYLHNldmVyaXR5X2xhYikgJT4lIAogICAgICAgICAgICAgICNmaWx0ZXIoQXNzYXkgJWluJSByZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UpICU+JSAKICAgICAgICAgICAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc2V2ZXJpdHlfbGFiLCB2YWx1ZXNfZnJvbSA9IE5QWCx2YWx1ZXNfZm4gPSBtZWRpYW4pCiAgICAgICAgICAgICwgYnk9YygiZ2VuZSI9IkFzc2F5IikpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1nZW5lKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImdlbmVfY3QiKSAlPiUKICByZWxvY2F0ZShzZXZlcmUsIG1vZGVyYXRlLCBtaWxkLCBjb252YWxlc2NlbmNlKQoKCiMjIGxlZ2VuZHMKY29sX25weCA8LSBjb2xvclJhbXAyKGMobWluKG1hdF9ucHgsbmEucm0gPSBUKSwKICAgICAgICAgICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgICAgICAgICAgbWF4KG1hdF9ucHgsbmEucm0gPSBUKS8yLAogICAgICAgICAgICAgICAgICAgICAgICBtYXgobWF0X25weCxuYS5ybSA9IFQpKSwKICAgICAgICAgICAgICAgICAgICAgIGMoIiNlZGY4ZTkiLCIjYmFlNGIzIiwgIiM3NGM0NzYiLCIjMjM4YjQ1IikpCgojbWF0X25weCA8LSBtYXRfbnB4ICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHNjYWxlczo6cmVzY2FsZSguLCB0bz1jKDQsMCkpKSkKY2VsbF9mcmVxX2NvbG9yIDwtIGNvbG9yUmFtcDIoYygwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbihjZWxsdHlwZV9sMl9mcmVxJFBlcmNlbnRhZ2UsbmEucm0gPSBUKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuKGNlbGx0eXBlX2wyX2ZyZXEkUGVyY2VudGFnZSxuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoY2VsbHR5cGVfbDJfZnJlcSRQZXJjZW50YWdlLG5hLnJtID0gVCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCIjZjJmMGY3IiwiI2NiYzllMiIsIiM5ZTlhYzgiLCIjNmE1MWEzIikpCgpsZ2RfbnB4ID0gTGVnZW5kKHRpdGxlID0gIk5QWCIsIGNvbF9mdW4gPSBjb2xfbnB4LAogICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZT02LGZvbnRmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplPTYpKQoKbGdkX2dleCA9IExlZ2VuZCh0aXRsZSA9ICJHRVgiLCBjb2xfZnVuID0gc2NhbGVkXzAxX2NvbCwKICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9Nixmb250ZmFjZT0iYm9sZCIpLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZT02KSkKCmxnZF9jZWxsdHlwZV9mcmVxID0gTGVnZW5kKHRpdGxlID0gIkNlbGwgZnJlcXVlbmN5XG5vZiBDRDQ1KyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9mdW4gPSBjZWxsX2ZyZXFfY29sb3IsCiAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplPTYsZm9udGZhY2U9ImJvbGQiKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemU9NikpCgpsZ2Rfc2V2ZXJpdHkgPSBMZWdlbmQodGl0bGUgPSAiU2V2ZXJpdHkgZ3JvdXAiLCAKICAgICAgICAgICAgICAgICAgICAgIGF0ID0gYygic2V2ZXJlIiwibW9kZXJhdGUiLCJtaWxkIiwiY29udmFsZXNjZW5jZSIpLAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2dwID0gZ3BhcihmaWxsID0gYygiI2NhMDAyMCIsIiNmNGE1ODIiLCIjOTJjNWRlIiwiZ3JleTUwIikpLAogICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplPTYsZm9udGZhY2U9ImJvbGQiKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemU9NikpCgoKbGdkX2NlbGx0eXBlID0gTGVnZW5kKHRpdGxlID0gIkNlbGx0eXBlcyIsIAogICAgICAgICAgICAgICAgICAgICAgYXQgPSBjKCJEQyIsIk1vbm9jeXRlcyIsIk5LIiwiZ2RUIiwiQiIsIkNENCsgVCIsIkNEOCsgVCIpLAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2dwID0gZ3BhcihmaWxsID0gYygiI2NhNTM2OSIsIiM2ODhiY2MiLCIjODc2MWNjIiwgIiNhZTk1M2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI2MzNjFhYSIsIiM2OGE3NDgiLCIjY2M2OTNkIikpLAogICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAjbnJvdyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9Nixmb250ZmFjZT0iYm9sZCIpLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZT02KSkKCmxnZF9jZWxsdHlwZV8yID0gTGVnZW5kKHRpdGxlID0gIkNlbGx0eXBlcyIsIAogICAgICAgICAgICAgICAgICAgICAgYXQgPSBjKCJtREMiLCJwREMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDE0IG1vbm9jeXRlcyIsIkNEMTYgbW9ub2N5dGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTksgQ0Q1NmRpbSBDRDE2KyIsIk5LIENENTZkaW0iLCJOS0NENTZicmlnaHQiLCJOSyBwcm9saWYuIiwiTktUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmQyKyBnZFQiLCJWZDItIGdkVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkIgbmFpdmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCIG1lbW9yeSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBsYXNtYSBjZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNENCBuYWl2ZSIsICJDRDQgVHJlZyBDRDgwKyIsICJDRDQgVHJlZyBDRDgwLSIsICJDRDQgVGZoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0Q0IGVmZmVjdC4gYWN0aXZhdGVkIiwiQ0Q0IGVmZmVjdC4gbWVtb3J5IiwiQ0Q0IHRyYW5zLm1lbW9yeSIsIkNEIGNlbnRyYWwgbWVtb3J5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0Q4IG5haXZlIiwgIkNEOCB0cmFucy4gbWVtb3J5IiwiQ0Q4VGZoIiwiQ0Q4IGVmZmVjdC4gbWVtb3J5IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIywoTDJfY29sb3JzKSwKICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9ncCA9IGdwYXIoZmlsbCA9IEwyX2NvbG9ycyksCiAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgIG5jb2w9MSwKICAgICAgICAgICAgICAgICAgICAgICNucm93ID0gNCwKICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZT02LGZvbnRmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplPTYpKQoKY2lyY2xlX3NpemUgPSB1bml0KDEsICJzbnBjIikgIyBzbnBjIHVuaXQgZ2l2ZXMgeW91IGEgc3F1YXJlIHJlZ2lvbgoKIyMgPT0gY2lyY29zLmhlYXRtYXAuZ2V0Lnggc3RhcnQgPT09PQoKIyMgQSBmdW5jdGlvbiB0byBleHRyYWN0IHJvdyBpbmRpY2llcywgdXNlZnVsIGZvciBsYWJlbGxpbmcKCiMjIHNvdXJjZTogaHR0cHM6Ly9yZHJyLmlvL2dpdGh1Yi9qb2tlcmdvby9jaXJjbGl6ZS9zcmMvUi9jaXJjb3MuaGVhdG1hcC5SCiMgPT0gdGl0bGUKIyBHZXQgdGhlIHgtcG9zaXRpb24gZm9yIGhlYXRtYXAgcm93cwojCiMgPT0gcGFyYW0KIyAtcm93X2luZCBBIHZlY3RvciBvZiByb3cgaW5kaWNpZXMuCiMKIyA9PSB2YWx1ZQojIEEgdGhyZWUtY29sdW1uIGRhdGEgZnJhbWUgb2YgdGhlIHNlY3RvciwgdGhlIHgtcG9zaXRpb25zIG9uIHRoZSBjb3JyZXNwb25kaW5nIHNlY3RvcnMsIGFuZCB0aGUgb3JpZ2luYWwgcm93IGluZGljaWVzLgpjaXJjb3MuaGVhdG1hcC5nZXQueCA9IGZ1bmN0aW9uKHJvd19pbmQpIHsKCWVudiA9IGNpcmNvcy5wYXIoIl9fdGVtcGVudl9fIikKCXNwbGl0ID0gZW52JGNpcmNvcy5oZWF0bWFwLnNwbGl0CgoJcm93X2luZF9sdCA9IHNwbGl0KHJvd19pbmQsIHNwbGl0W3Jvd19pbmRdKQoJcm93X2luZF9sdCA9IHJvd19pbmRfbHRbc2FwcGx5KHJvd19pbmRfbHQsIGxlbmd0aCkgPiAwXQoJCgl4ID0gTlVMTAoJZm9yKGkgaW4gcm93X2luZF9sdCkgewoKCQlzdWJzZXQgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInN1YnNldCIsIHNlY3Rvci5pbmRleCA9IHNwbGl0W2lbMV1dKQoJCW9yZGVyID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJyb3dfb3JkZXIiLCBzZWN0b3IuaW5kZXggPSBzcGxpdFtpWzFdXSkKCQkKCQl4ID0gYyh4LCB3aGljaCgoMTpsZW5ndGgoc3BsaXQpKVtzdWJzZXRdW29yZGVyXSAlaW4lIGkpKQoJfQoJZGYgPSBkYXRhLmZyYW1lKHNlY3RvciA9IHJlcChuYW1lcyhyb3dfaW5kX2x0KSwgdGltZXMgPSBzYXBwbHkocm93X2luZF9sdCwgbGVuZ3RoKSksIAoJCXggPSB4IC0gMC41LCByb3dfaW5kID0gdW5saXN0KHJvd19pbmRfbHQpKQoJcm93bmFtZXMoZGYpID0gTlVMTAoJZGYKfQojIyA9PSBjaXJjb3MuaGVhdG1hcC5nZXQueCBlbmQgPT09PQoKdG90YWxfc2VjdGlvbnMgPC0gbGVuZ3RoKGxldmVscyhtYXQkY2VsbHR5cGUpKQoKCiMjIHRoZSBmdW5jdGlvbiB0byBtYWtlIHRoZSBwbG90CmNpcmNsaXplX3Bsb3QgPSBmdW5jdGlvbigpIHsKICAgIGNpcmNvcy5jbGVhcigpCgogIGNpcmNvcy5wYXIoZ2FwLmFmdGVyID0gYyhyZXAoMix0b3RhbF9zZWN0aW9ucy0xKSwxMCksIAogICAgICAgICAgICAgcG9pbnRzLm92ZXJmbG93Lndhcm5pbmcgPSBUKQojY2lyY29zLnBhcihzdGFydC5kZWdyZWUgPSA5MCwgZ2FwLmRlZ3JlZSA9IDEwLGdhcC5hZnRlciA9IGMoMykpCgojIyBkdW1teSB0cmFjaywgaW52aXNpYmxlLCBuZWVkZWQgZm9yIHNwbGl0CmNpcmNvcy5oZWF0bWFwKG1hdF9nZXgsCiAgICAgICAgICAgICAgIGNsdXN0ZXIgPSBGLAogICAgICAgICAgICAgICBzcGxpdCA9IGRyb3BsZXZlbHMobWF0JGNlbGx0eXBlKSwKICAgICAgICAgICAgICAgY29sID0gY29sb3JSYW1wMihjKC0yLCAwLCAyKSwgYygid2hpdGUiLCAid2hpdGUiLCAid2hpdGUiKSksIAogICAgICAgICAgICAgICB0cmFjay5oZWlnaHQgPSAwLjIxLCMwLjAwMDAwMDAwMSwKICAgICAgICAgICAgICAgKQoKIyMgY2VsbHR5cGUgYW5ub3RhdGlvbiB0cmFjawpjaXJjb3MuaGVhdG1hcChtYXQgJT4lIGNvbHVtbl90b19yb3duYW1lcygiZ2VuZV9jdCIpICU+JSBkcGx5cjo6c2VsZWN0KGNlbGx0eXBlKSwgCiAgICAgICAgICAgICAgIGNvbCA9IEwyX2NvbG9ycywgCiAgICAgICAgICAgICAgIHRyYWNrLmhlaWdodCA9IDAuMDgsCiAgICAgICAgICAgICAgIHJvd25hbWVzLnNpZGUgPSAibm9uZSIsCiApCgojIyBjZWxsdHlwZSBmcmVxdWVuY3kgdHJhY2sKY2lyY29zLmhlYXRtYXAobWF0ICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoImdlbmVfY3QiKSAlPiUgdHJhbnNtdXRlKENlbGxUeXBlX0wyID0gY2VsbHR5cGUpICU+JSBsZWZ0X2pvaW4oY2VsbHR5cGVfbDJfZnJlcSwgYnk9IkNlbGxUeXBlX0wyIikgJT4lIHB1bGwoUGVyY2VudGFnZSksIGNvbCA9IGNlbGxfZnJlcV9jb2xvciwgdHJhY2suaGVpZ2h0ID0gMC4wMSkKCiMjIGNlbGx0eXBlIGFubm90YXRpb24gdGFjayBuYW1pbmcKY2lyY29zLnRyYWNrUGxvdFJlZ2lvbih0cmFjay5pbmRleCA9IDEsIHBhbmVsLmZ1biA9IGZ1bmN0aW9uKHgsIHkpIHsKICB4bGltID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ4bGltIikKICB5bGltID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ5bGltIikKICBzZWN0b3IubmFtZSA9IGdldC5jZWxsLm1ldGEuZGF0YSgic2VjdG9yLmluZGV4IikKICBjaXJjb3MudGV4dChtZWFuKHhsaW0pLAogICAgICAgICAgICAgIHlsaW1bMV0gKyAuMSwgCiAgICAgICAgICAgICAgc2VjdG9yLm5hbWUsIAogICAgICAgICAgICAgIGZhY2luZyA9ICJjbG9ja3dpc2UiLCAKICAgICAgICAgICAgICBuaWNlRmFjaW5nID0gVFJVRSwgY2V4PS42LAogICAgICAgICAgICAgIGFkaiA9IGMoMCwgMC41KSwgY29sID0gImdyZXk0MCIpCn0sIGJnLmJvcmRlciA9IE5BKQoKIyMgY2VsbHR5cGUgZ2VuZSBleHByZXNzaW9uIHRyYWNrCmNpcmNvcy5oZWF0bWFwKG1hdF9nZXgsCiAgICAgICAgICAgICAgIGNsdXN0ZXIgPSBGLCAKICAgICAgICAgICAgICAgY29sID0gc2NhbGVkXzAxX2NvbCwgCiAgICAgICAgICAgICAgIHRyYWNrLmhlaWdodCA9IDAuMDQsCiAgICAgICAgICAgICAgICMgcm93bmFtZXMuc2lkZSA9ICJvdXRzaWRlIiwKICAgICAgICAgICAgICAgYmcuYm9yZGVyID0gImdyZXk4MCIsIAogICAgICAgICAgICAgICBiZy5sd2QgPSAuMSwKICAgICAgICAgICAgICAgYmcubHR5ID0gLjEsIAogICAgICAgICAgICAgICBzaG93LnNlY3Rvci5sYWJlbHMgPSBGCikKCiMjIHBsYXNtYSBOUFggdHJhYwpjaXJjb3MuaGVhdG1hcChtYXRfbnB4LCBjb2wgPSBjb2xfbnB4LCB0cmFjay5oZWlnaHQgPSAwLjA5KQoKIyMgYWRkIGFubm90YXRpb24gdG8gcm93IG9mIG5weCBkYXRhCmNpcmNvcy50cmFjayh0cmFjay5pbmRleCA9IGdldC5jdXJyZW50LnRyYWNrLmluZGV4KCksIHBhbmVsLmZ1biA9IGZ1bmN0aW9uKHgsIHkpIHsKICAgIGlmKENFTExfTUVUQSRzZWN0b3IubnVtZXJpYy5pbmRleCA9PSB0b3RhbF9zZWN0aW9ucykgeyAjIHRoZSBsYXN0IHNlY3RvciAjMjYKICAgICAgIyMgY29udmFsCiAgICAgICAgY2lyY29zLnJlY3QoQ0VMTF9NRVRBJGNlbGwueGxpbVsyXSArIGNvbnZlcnRfeCgxLCAibW0iKSwgMCwKICAgICAgICAgICAgICAgICAgICBDRUxMX01FVEEkY2VsbC54bGltWzJdICsgY29udmVydF94KDQsICJtbSIpLCAxLCAjMTAKICAgICAgICAgICAgICAgICAgICBjb2wgPSAiZ3JleTUwIiwgYm9yZGVyID0gTkEpCiAgICAgICMjIG1pbGQgIAogICAgICBjaXJjb3MucmVjdChDRUxMX01FVEEkY2VsbC54bGltWzJdICsgY29udmVydF94KDEsICJtbSIpLCAxLAogICAgICAgICAgICAgICAgICAgIENFTExfTUVUQSRjZWxsLnhsaW1bMl0gKyBjb252ZXJ0X3goNCwgIm1tIiksIDIsICM1CiAgICAgICAgICAgICAgICAgICAgY29sID0gIiM5MmM1ZGUiLCBib3JkZXIgPSBOQSkKICAgICAgIyMgbW9kZXJhdGUKICAgICAgICBjaXJjb3MucmVjdChDRUxMX01FVEEkY2VsbC54bGltWzJdICsgY29udmVydF94KDEsICJtbSIpLCAyLAogICAgICAgICAgICAgICAgICAgIENFTExfTUVUQSRjZWxsLnhsaW1bMl0gKyBjb252ZXJ0X3goNCwgIm1tIiksIDMsICMxMAogICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjZjRhNTgyIiwgYm9yZGVyID0gTkEpCiAgICAgICAgIyMgc2V2ZXJlCiAgICAgICAgY2lyY29zLnJlY3QoQ0VMTF9NRVRBJGNlbGwueGxpbVsyXSArIGNvbnZlcnRfeCgxLCAibW0iKSwgMywKICAgICAgICAgICAgICAgICAgICBDRUxMX01FVEEkY2VsbC54bGltWzJdICsgY29udmVydF94KDQsICJtbSIpLCA0LCAjMTAKICAgICAgICAgICAgICAgICAgICBjb2wgPSAiI2NhMDAyMCIsIGJvcmRlciA9IE5BKQogICAgICAgCiAgICB9Cn0sIGJnLmJvcmRlciA9IE5BKQoKIyMgQW5ub3RhdGUgc291cmNlIGdlbmVzCnJvd19pbmQgPC0gbWF0ICU+JSBmaWx0ZXIoZ2VuZSVpbiVkZl9saW5rJHNvdXJjZV9nZW5lKSAlPiUgbXV0YXRlKHJvd25hbWUgPSBhcy5pbnRlZ2VyKHJvd25hbWUpKSAlPiUgcHVsbChyb3duYW1lKQpwb3Nfc28gPSBjaXJjb3MuaGVhdG1hcC5nZXQueChyb3dfaW5kKQpwb3Nfc28gPC0gcG9zX3NvICU+JSByaWdodF9qb2luKG1hdCAlPiUgZmlsdGVyKGdlbmUlaW4lZGZfbGluayRzb3VyY2VfZ2VuZSkgJT4lIG11dGF0ZShyb3dfaW5kID0gYXMuaW50ZWdlcihyb3duYW1lKSksIGJ5PSJyb3dfaW5kIikKCiMjIEFubm90YXRlIHJlY2lwaWVudCBnZW5lcwpyb3dfaW5kIDwtIG1hdCAlPiUgZmlsdGVyKGdlbmUlaW4lZGZfbGluayRyZWNpcGllbnRfZ2VuZSkgJT4lIG11dGF0ZShyb3duYW1lID0gYXMuaW50ZWdlcihyb3duYW1lKSkgJT4lIHB1bGwocm93bmFtZSkKcG9zX3JlYyA9IGNpcmNvcy5oZWF0bWFwLmdldC54KHJvd19pbmQpCnBvc19yZWMgPC0gcG9zX3JlYyAlPiUgcmlnaHRfam9pbihtYXQgJT4lIGZpbHRlcihnZW5lJWluJWRmX2xpbmskcmVjaXBpZW50X2dlbmUpICU+JSBtdXRhdGUocm93X2luZCA9IGFzLmludGVnZXIocm93bmFtZSkpLCBieT0icm93X2luZCIpCgpwb3MgPC0gYmluZF9yb3dzKHBvc19zbywgcG9zX3JlYykKCiMjIGxhYmxlIGFsbCBvdGhlciBnZW5lcwoKIyMgQW5ub3RhdGUgc291cmNlIGdlbmVzCnJvd19pbmRfYWxsb3RoZXJzIDwtIG1hdCAlPiUgZmlsdGVyKCFnZW5lICVpbiUgYyhkZl9saW5rJHNvdXJjZV9nZW5lLGRmX2xpbmskcmVjaXBpZW50X2dlbmUpKSAlPiUgbXV0YXRlKHJvd25hbWUgPSBhcy5pbnRlZ2VyKHJvd25hbWUpKSAlPiUgcHVsbChyb3duYW1lKQoKcG9zX2FsbG90aGVycyA9IGNpcmNvcy5oZWF0bWFwLmdldC54KHJvd19pbmRfYWxsb3RoZXJzKSAlPiUgCiAgbGVmdF9qb2luKG1hdCAlPiUgbXV0YXRlKHJvd19pbmQgPSBhcy5pbnRlZ2VyKHJvd25hbWUpKSwgYnk9InJvd19pbmQiKQoKIyMgam9pbiBhbGwgbGFibGUgaW5mbwpwb3NfYWxsIDwtIGJpbmRfcm93cyhwb3MgJT4lIG11dGF0ZShjb2wgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gLjQpLAogICAgICAgICAgICAgICAgICAgICBwb3NfYWxsb3RoZXJzICU+JSBtdXRhdGUoY29sID0gImdyZXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT0uMikpCgpjaXJjb3MubGFiZWxzKHBvc19hbGwkc2VjdG9yLCAKICAgICAgICAgICAgICBwb3NfYWxsJHgsCiAgICAgICAgICAgICAgY29ubmVjdGlvbl9oZWlnaHQgPS4wMSwKICAgICAgICAgICAgICBjZXggPXBvc19hbGwkc2l6ZSwKICAgICAgICAgICAgICBzaWRlPSJpbnNpZGUiLAogICAgICAgICAgICAgIGNvbCA9IHBvc19hbGwkY29sLCAKICAgICAgICAgICAgICBsYWJlbHMgPSBwb3NfYWxsJGdlbmUpCgojIyBhZGQgY29ubmVjdGlvbnMKZm9yKGkgaW4gc2VxX2xlbihucm93KGRmX2xpbmspKSkgewoKCiAgICAgICAgY2lyY29zLmhlYXRtYXAubGluayhkZl9saW5rJGZyb21faW5kZXhbaV0sCiAgICAgICAgICAgICAgICAgICAgICAgIGRmX2xpbmskdG9faW5kZXhbaV0sCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHJhbmRfY29sb3IoMSksCiAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICBsd2QgPSAxLjUsCiAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbmFsID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgYXJyLndpZHRoID0gLjEyNSwKICAgICAgICAgICAgICAgICAgICAgICAgYXJyLmxlbmd0aCA9IC4yLAogICAgICAgICAgICAgICAgICAgICAgICBhcnIubHdkID0gLjEsCiAgICAgICAgICAgICAgICAgICAgICAgYXJyLmNvbCA9ICJibGFjayIpCn0KCgogIGNpcmNvcy5jbGVhcigpCn0KCmxpYnJhcnkoZ3JpZEJhc2UpCnBkZihwYXN0ZTAocmVzdWx0LnRtcC5kaXIscGRmX2ZpbGVfbmFtZSwiLnBkZiIpKSMscGFwZXIgPSAiYTRyIikKcGxvdC5uZXcoKQoKY2lyY2xlX3NpemUgPSB1bml0KDEsICJzbnBjIikgIyBzbnBjIHVuaXQgZ2l2ZXMgeW91IGEgc3F1YXJlIHJlZ2lvbgoKcHVzaFZpZXdwb3J0KHZpZXdwb3J0KHggPSAwLjUsIHkgPSAxLCMwLjUsCiAgICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IGNpcmNsZV9zaXplLCAKICAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IGNpcmNsZV9zaXplLAogICAganVzdCA9ICBjKCJjZW50ZXIiLCAidG9wIikpKQpwYXIob21pID0gZ3JpZE9NSSgpLCBuZXcgPSBUUlVFKQpjaXJjbGl6ZV9wbG90KCkKdXBWaWV3cG9ydCgpCgpkcmF3KHBhY2tMZWdlbmQobGdkX2dleCwgbGdkX25weCwKICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiksCiAgICAgeSA9IHVuaXQoMSwgIm5wYyIpIC0gY2lyY2xlX3NpemUqLjEsIAogICAgIHggPSB1bml0KDEuMDQsIm5wYyIpIC0gY2lyY2xlX3NpemUqMC4xLAogICAgIGp1c3QgPSBjKCJjZW50ZXIiLCJyaWdodCIpKQoKZHJhdyhwYWNrTGVnZW5kKGxnZF9jZWxsdHlwZV9mcmVxLAogICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhvcml6b250YWwiKSwKICAgICAjeSA9IHVuaXQoMSwgIm5wYyIpIC0gY2lyY2xlX3NpemUqLjEsIAogICAgIHggPSB1bml0KDEuMDQsIm5wYyIpIC0gY2lyY2xlX3NpemUqMC4xLAogICAgIGp1c3QgPSBjKCJjZW50ZXIiLCJyaWdodCIpKQoKCmRyYXcocGFja0xlZ2VuZChsZ2Rfc2V2ZXJpdHksCiAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpLAogICAgIHkgPSB1bml0KDEsICJucGMiKSAtIGNpcmNsZV9zaXplKi44LCAKICAgICB4ID0gdW5pdCgxLjAsIm5wYyIpIC0gY2lyY2xlX3NpemUqMC4xMSwKICAgICBqdXN0ID0gYygiYm90dG9tIiwibGVmdCIpKQpkZXYub2ZmKCkKcmV0dXJuKGNpcmNsaXplX3Bsb3QoKSkKfQpgYGAKCmBgYHtyfQpteV9uaWNlX2NpcmNvc3Bsb3QoYXNzYXlzMnBsb3RfY2lyY29zID0gcmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlLAogICAgICAgICAgICAgICAgICAgc2NhbGVfcmFuZ2UgPSBjKDAsMSksCiAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uX3RocmVzaG9sZCA9IDAuNSwKICAgICAgICAgICAgICAgICAgIHBkZl9maWxlX25hbWUgPSAiSW1tdW5lQ2VsbF9Qcm90ZWluX0NpcmNvc1Bsb3Rfc2V2ZXJpdHltb2R1bGUiCiAgICAgICAgICAgICAgICAgICApCmBgYAoKIyMgRmlndXJlIDdFCmBgYHtyfQpteV9jb21wYXJpc29uc19zZXZlcmVfY29udiA8LSBsaXN0KGMoInNldmVyZSIsICJtb2RlcmF0ZSIpLCBjKCJtb2RlcmF0ZSIsICJtaWxkIiksIGMoInNldmVyZSIsICJtaWxkIiksYygibWlsZCIsImNvbnZhbGVzY2VuY2UiKSkKCnNlbGVjdGlvbiA8LSBjKCJMR0FMUzkiLCJJTDQiLCJDRDI3NCIsIkNENzAiKQoKKHNldmVyaXR5X2xpZ2FuZF9ucHggPC0gZGZfYWN1dGVfcGF0Y2x1c3RfaW5jbF9jb252ICU+JSAKCiAgICBkcGx5cjo6ZmlsdGVyKEFzc2F5ICVpbiUgYyhzZWxlY3Rpb24pKSAlPiUgCiAgICBtdXRhdGUoQXNzYXkgPSBmYWN0b3IoQXNzYXksIGxldmVscyA9IGMoc2VsZWN0aW9uKSkpICU+JSAKICAgIGdncGxvdChhZXMoeD1zZXZlcml0eV9sYWIsIHk9TlBYLCBjb2xvcj1zZXZlcml0eV9sYWIsIGZpbGw9c2V2ZXJpdHlfbGFiKSkgKyAKICAgIGdlb21fdmlvbGluKHRyaW0gPSBGLGFscGhhPS45KSArCiAgICBnZW9tX2ppdHRlcihzaXplPTAuMjUsc2hvdy5sZWdlbmQgPSBGLCB3aWR0aCA9IDAuMDUsIGFscGhhPTEsIGNvbG9yPSJncmV5MjAiKSArCiAgICBnZW9tX2JveHBsb3QoYWxwaGE9Ljcsd2lkdGg9MC4yNSxvdXRsaWVyLnNoYXBlID0gTkEsY29sb3I9ImJsYWNrIiwgZmF0dGVuID0gMixsd2Q9LjI1LHNob3cubGVnZW5kID0gRikgKwogICAgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwuc2VwID0gIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICBoaWRlLm5zID0gVCwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLnNpZ25pZiIgLAogICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gLjUsCiAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT0yLAogICAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IC4yLAogICAgICAgICAgICAgICAgICAgICAgIGNvbXBhcmlzb25zID1teV9jb21wYXJpc29uc19zZXZlcmVfY29udiwKICAgICAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYpICsKICAgIGZhY2V0X3dyYXAofkFzc2F5LG5yb3cgPSAyLHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnMoeD0iIiwKICAgICAgICAgY29sb3I9TlVMTCwKICAgICAgICAgZmlsbD1OVUxMKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gcGF0aWVudF9rY2x1c3QzX2xhYl9jb252KSkKYGBgCgojIyBGaWd1cmUgN0YKCmBgYHtyfQojRkFDc19kYXRhICU+JSBkaXN0aW5jdChmZWF0dXJlKQoKY2VsbHN1YnNldC5vcmRlciA8LSBGQUNzX2RhdGEgJT4lIAogIGZpbHRlcihmZWF0dXJlJWluJWMoIkNENCtDRDM4K0hMQURSKyBUIGNlbGxzIiwiQ0Q4K0NEMzgrSExBRFIrIFQgY2VsbHMiKSwKIyAgICBncmVwbCgiVHJlZyIsZmVhdHVyZSkKICAgICkgJT4lIGRpc3RpbmN0KGZlYXR1cmUpICU+JSBwdWxsKCkKCnRlc3RfY29ycmVsYXRpb25faW5wdXQgPC0gRkFDc19kYXRhICU+JSAKICBmaWx0ZXIoVGltZT09IkFjdXRlIiwKICAgICAgICAgZmVhdHVyZSVpbiUKICAgICAgICAgICBjKAogICAgICAgICAgICJDRDQrQ0QzOCtITEFEUisgVCBjZWxscyIsCiAgICAgICAgICAgIkNEOCtDRDM4K0hMQURSKyBUIGNlbGxzIgogICAgICAgICApCiAgKSAlPiUgCiAgdHJhbnNtdXRlKHNhbXBsZV9pZCA9IHNhbXBsZUlELAogICAgICAgICAgICB0eXBlX2ZlYXR1cmUgPSBwYXN0ZTAoIkZBQ1NfIixmZWF0dXJlKSwKICAgICAgICAgICAgdmFsdWUpICU+JSAKICBwaXZvdF93aWRlcih2YWx1ZXNfZnJvbSA9IHZhbHVlLCBuYW1lc19mcm9tID0gdHlwZV9mZWF0dXJlKSAlPiUgCiAgaW5uZXJfam9pbigKICAgICMjIFBsYXNtYSBwcm90ZWluIGRhdGEgZnJvbSB0aGlzIHBhcGVyCiAgICBkYXRhLmxvbmcgJT4lIAogICAgICBpbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSkgJT4lIAogICAgICBmaWx0ZXIoQXNzYXkgJWluJSByZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UpICU+JSAKICAgICAgdHJhbnNtdXRlKAogICAgICAgIHNhbXBsZV9pZCwKICAgICAgICB0eXBlX2Fzc2F5ID0gcGFzdGUwKCJQRUFfIixBc3NheSksCiAgICAgICAgTlBYKSAlPiUgCiAgICAgIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gTlBYLCBuYW1lc19mcm9tID0gdHlwZV9hc3NheSksCiAgICBieT0ic2FtcGxlX2lkIikKYGBgCgoKYGBge3IgfQp0ZXN0X2NvcnJlbGF0aW9uX3JlcyA8LSB0ZXN0X2NvcnJlbGF0aW9uX2lucHV0ICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoInNhbXBsZV9pZCIpICU+JSAKICBjb3JyZWxhdGlvbihwX2FkanVzdCA9ICJmZHIiLG1ldGhvZCA9ICJzcGVhcm1hbiIscmVkdW5kYW50ID0gRikgJT4lIAogIHRpYmJsZSgpCmBgYAoKCmBgYHtyfQpjb3IuZyA8LSB0ZXN0X2NvcnJlbGF0aW9uX3JlcyAlPiUgCiAgZmlsdGVyKFBhcmFtZXRlcjEhPVBhcmFtZXRlcjIpICU+JSAKICBmaWx0ZXIoCiAgICAhZ3JlcGwoIlBFQSIsUGFyYW1ldGVyMSksCiAgICAhZ3JlcGwoIkZBQ1MiLFBhcmFtZXRlcjIpCiAgKSAlPiUgCiAgIGFycmFuZ2UoLWFicyhyaG8pKSAlPiUgCiAgZmlsdGVyKHA8PTAuMDUpICU+JSAKICAgICB0cmFuc211dGUoZnJvbSA9IFBhcmFtZXRlcjEsIyA9IHN0cl9yZW1vdmUoUGFyYW1ldGVyMSwgIkZBQ1NfIiksCiAgICAgICAgICAgIHRvID0gUGFyYW1ldGVyMiwjID0gc3RyX3JlbW92ZShQYXJhbWV0ZXIyLCAiUEVBXyIpLAogICAgICAgICAgICByaG8sCiAgICAgICAgICAgIHAKICAgICAgICAgICAgKSAlPiUgCiAgYXNfdGJsX2dyYXBoKGRpcmVjdGVkID0gRikKCm5vZGVfdGFibGUgPC0gYXNfdGliYmxlKGNvci5nKSAlPiUgCiAgc2VwYXJhdGUobmFtZSwgaW50bz1jKCJvbWljcyIsImZlYXR1cmUiKSxzZXAgPSAiXyIscmVtb3ZlID0gRikgCmBgYAoKCmBgYHtyfQoocHJvdGVpbl9jZWxsbnVtX2Nvcm5ldCA8LSBjb3IuZyAlPiUgCiAgaW5uZXJfam9pbihub2RlX3RhYmxlLGJ5PSJuYW1lIikgJT4lIAogICAgYWN0aXZhdGUobm9kZXMpICU+JSAgIyBTZXRzIGNvbnRleHQgdG8gbm9kZXMgLT4gc3Vic2VxdWVudCBvcGVyYXRpb25zIGFyZSBwZXJmb3JtZWQgb24gbm9kZXMKICBtdXRhdGUoZGVnID0gY2VudHJhbGl0eV9kZWdyZWUoKSkgJT4lIAogIGZpbHRlcighbm9kZV9pc19pc29sYXRlZCgpKSAlPiUgICMgUmVtb3ZlcyBub2RlcyB0aGF0IGFyZSBpc29sYXRlZC9kbyBub3QgaGF2ZSBhbnkgZm9sbG93ZXIgZWRnZXMKIyBjcmVhdGVfbGF5b3V0KGxheW91dCA9ICJpZ3JhcGgiLCBhbGdvcml0aG0gPSAiZnIiKSAlPiUgCiAgY3JlYXRlX2xheW91dChsYXlvdXQgPSAic3RyZXNzIikgJT4lICAjZnIKICBnZ3JhcGgoKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMoY29sb3IgPSByaG8pLAogICAgICAgICAgICAgICAgICAgIyAgICBhbHBoYSA9IDAuOQogICAgICAgICAgICAgICAgICAgKSArICAKICBzY2FsZV9lZGdlX2NvbG9yX2NvbnRpbnVvdXMobG93PSJ0aGlzdGxlMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2g9ImRhcmtyZWQiKSArCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhjb2xvciA9IG9taWNzLAogICAgICAgICAgICAgICAgICAgICAgc2l6ZT0gaWZlbHNlKG9taWNzPT0iRkFDUyIsMywxKSksCiAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IGZlYXR1cmUsCiAgICAgICAgICAgICAgICAgICAgIGFscGhhPSBpZmVsc2UoZGVnPjEsMSwuNSkKICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICBjb2xvcj0iYmxhY2siLAogICAgICAgICAgICAgICAgIHNpemU9MS41LAogICAgICAgICAgICAgICAgIHJlcGVsID0gVCxzaG93LmxlZ2VuZCA9IEYKICAgICAgICAgICAgICAgICAgICAgKSArCiAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZSA9IGMoMC41LCAxKSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgICBndWlkZXMoY29sb3I9IGd1aWRlX2NvbG9yYmFyKGJhcmhlaWdodCA9IDEsIGJhcndpZHRoID0gLjEpKSArCgogICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCggc2l6ZT02KSwKICAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NikpIAoKKQoKYGBgCgoKIyBTZXNzaW9uIEluZm8KCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoKCiMgRmlndXJlIFBhbmVscwoKYGBge3IgZXZhbD1GQUxTRX0Kc291cmNlX3JtZCA8LSBmdW5jdGlvbihybWRfZmlsZSl7CiAga25pdHI6OmtuaXQocm1kX2ZpbGUsIG91dHB1dCA9IHRlbXBmaWxlKCkpCn0KCnNvdXJjZV9ybWQoIk1ha2VfbXlfZmlndXJlcGFuZWxzLlJtZCIpCgojIyBtYWtlIG9uZSBQZGYKbGlicmFyeShxcGRmKQpxcGRmOjpwZGZfY29tYmluZSgKICBpbnB1dCA9IGMoIi4uL01hbnVzY3JpcHQvRmlndXJlXzEucGRmIiwgCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV8yLnBkZiIsCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV8zLnBkZiIsIAogICAgICAgICAgICAiLi4vTWFudXNjcmlwdC9GaWd1cmVfNC5wZGYiLCAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzUucGRmIiwgCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV82LnBkZiIsCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV83LnBkZiIpLAogIG91dHB1dCA9ICIuLi9NYW51c2NyaXB0L0xhdXRlbmJhY2hfZXRhbF9tYWluZmlndXJlcy5wZGYiCikKCnFwZGY6OnBkZl9jb21iaW5lKAogIGlucHV0ID0gYygiLi4vTWFudXNjcmlwdC9GaWd1cmVfMV9TMS5wZGYiLCAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzFfUzIucGRmIiwgCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV8xX1MzLnBkZiIsIAogICAgICAgICAgICAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzJfUzQucGRmIiwKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzJfUzUucGRmIiwgCiAgICAgICAgICAgIAogICAgICAgICAgICAiLi4vTWFudXNjcmlwdC9GaWd1cmVfM19TNi5wZGYiLCAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzNfUzcucGRmIiwgCiAgICAgICAgICAgIAogICAgICAgICAgICAiLi4vTWFudXNjcmlwdC9GaWd1cmVfNF9TOC5wZGYiLAogICAgICAgICAgICAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzVfUzkucGRmIgogICAgICAgICAgICApLAogIG91dHB1dCA9ICIuLi9NYW51c2NyaXB0L0xhdXRlbmJhY2hfZXRhbF9zdXBwbGVtZW50YXJ5ZmlndXJlcy5wZGYiCikKYGBgCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoK